登入功能是很常會遇到的需求,但往往要實作時都不知從何著手,其中一個原因它有一些設定上的步驟,通常做過一次就忘了,本篇文章就以最簡單的 Cookie 驗證做示範 (以 ASP.NET Core 專案為例)

一開始先實作驗證用的 Manager 類別

public class PersonModel
{
    [DisplayName("姓名")]
    public string Name { get; set; } = string.Empty;
    [DisplayName("手機")]
    public string Phone { get; set; } = string.Empty;
    [DisplayName("Email")]
    public string Email { get; set; } = string.Empty;
    [DisplayName("生日")]
    public DateTime? Birthday { get; set; } = null;
}
public interface IAuthManager
{
    bool AuthByNameAndPassword(string username, string password, out PersonModel person);
    PersonModel? GetPersonByName(string username);
}
public class AuthManager : IAuthManager
{
    private ConcurrentDictionary<string, string> _authData;
    private ConcurrentDictionary<string, PersonModel> _users;

    public AuthManager() 
    {
        _authData = new ConcurrentDictionary<string, string>();
        _authData.TryAdd("peter", "1234");
        _authData.TryAdd("john", "1234");

        _users= new ConcurrentDictionary<string, PersonModel>();
        _users.TryAdd("peter", new PersonModel
        {
            Name = "Peter",
            Birthday = new DateTime(1980, 6, 5),
            Email = "peter@gmail.com",
            Phone = "0922000000"
        });
        _users.TryAdd("john", new PersonModel
        {
            Name = "john",
            Birthday = new DateTime(1990, 5, 5),
            Email = "john@gmail.com",
            Phone = "0922000000"
        });
    }

    public bool AuthByNameAndPassword(string username, string password, out PersonModel person)
    {
        bool result = false;
        person = new PersonModel();

        if(_authData.ContainsKey(username)) 
        {
            if (_authData[username] == password)
            {
                result = true;
                person = _users[username];
            }
        }

        return result;
    }

    public PersonModel? GetPersonByName(string username) 
    {
        PersonModel? person = null;

        if (_authData.ContainsKey(username))
        {
            person = _users[username];
        }

        return person;
    }
}

再來是 Program.cs 上的設定

//auth
builder.Services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(option =>
{
    option.LoginPath = "/Home/Login";
});
builder.Services.AddAuthorization();

builder.Services.AddTransient<IAuthManager, AuthManager>();

app.UseAuthentication();
app.UseAuthorization();

然後是 Home Controller 上的實作

[HttpGet]
public IActionResult Login()
{
	return View();
}

[HttpPost]
public IActionResult Login(LoginModel model)
{
	if (!_authManager.AuthByNameAndPassword(model.UserName, model.Password, out PersonModel person))
	{
		return RedirectToAction("Login");
	}

	var claims = new List<Claim>
	{
		new Claim(ClaimTypes.Name, model.UserName),
		new Claim("email", person.Email),
	};

	var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
	var authProperties = new AuthenticationProperties
	{
		ExpiresUtc = DateTimeOffset.UtcNow.AddHours(3),
		IsPersistent = true
	};
	var _= HttpContext.SignInAsync(new ClaimsPrincipal(claimsIdentity), authProperties);

	return RedirectToAction("Info");
}

[Authorize]
public IActionResult Info()
{
	var data = HttpContext.User.Claims.First();
	string name = data.Value;
	PersonModel? person = _authManager.GetPersonByName(name);
	return View(person);
}

在需要登入的 Action 上加入 Authorize 即可

而登入的方法也很簡單,呼叫 await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme) 就可以了

參考資料