ASP.NET Core 3.0 登入機制實作(claims-based authentication)

我們開新專案時,專案範本可以選擇「個別使用者帳戶」驗證方式,這時候專案就會有登入的機制了,但是很多工程師都不這麼用,理由是:
1. 他是 core first 的方式,不是它們習慣的 db first。
2. 要客製化時要改很多code,感覺太麻煩。

不過有個時機可能會用到他,就是要整合第三方登入機制,如Facebook, Twitter..等等,因為只要設定一下,就可以了。

可以參考: https://docs.microsoft.com/zh-tw/aspnet/core/security/authentication/identity?view=aspnetcore-3.0&tabs=visual-studio

不過本文最主要的是要說明客製化的實作,也就是專案範本不選 「個別使用者帳戶」 驗證方式 ,實作說明如下

Step 1. 在 Startup.cs 的 ConfigureServices 宣告

public void ConfigureServices(IServiceCollection services)
{
//宣告增加驗證方式,使用 cookie 驗證
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(option =>{
    //瀏覽器會限制cookie 只能經由HTTP(S) 協定來存取
    option.Cookie.HttpOnly = true;
    //登入頁,未鄧入時會自動導到登入頁
    option.LoginPath = new PathString("/Account/Login");
    //登出網頁(可以省略)
    option.LogoutPath = new PathString("/Account/Logout");
    //登入有效時間
     option.ExpireTimeSpan = TimeSpan.FromMinutes(60);
     });        
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    //啟用 cookie 原則功能
    app.UseCookiePolicy();
    //啟用身分識別
    app.UseAuthentication();
    //啟用授權功能
    app.UseAuthorization();
    // 這三個前後次序不能對調喔
}

Step 2. 在 Controller 登入實作範例

[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(LoginVM model)
{
    if (ModelState.IsValid)
    {
        var Pwd = CryptoHelper.HashPassword(model.Password);
        var user= _context.User.FirstOrDefault(x=>x.Account== model.Account && x.Password==Pwd);
        if (user== null)
        {
             ViewBag.errMsg = "帳號或密碼輸入錯誤";
             return View(model);
        }
        //取得登入角色
        var RoleName =_context.Role.FirstOrDefault(x=>x.Id==user.RoleId).RoleName;
        //建立 Claim,也就是要寫到 Cookie 的內容
        var claims = new[] { new Claim("UserId", user.Id.ToString()), new Claim("Account", user.Account), new Claim("Name", user.Name), new Claim(ClaimTypes.Role, RoleName) }; 
        //建立證件,類似你的駕照或護照
        ClaimsIdentity claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
        //將 ClaimsIdentity 設定給 ClaimsPrincipal (持有者) 
        ClaimsPrincipal principal = new ClaimsPrincipal(claimsIdentity);

        //登入動作
        await HttpContext.SignInAsync(principal,new AuthenticationProperties()
               {
                   //是否可以被刷新
                   AllowRefresh = false,
                   // 設置了一個 1 天 有效期的持久化 cookie
                   IsPersistent = true,
                   ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1)
               });
         return View(model);
}

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *