首頁 > 軟體

.NET CORE 鑑權的實現範例

2022-02-20 10:00:36

基礎資訊

1.什麼是鑑權授權?

  • 鑑權是驗證使用者是否擁有存取系統的權利,授權是判斷使用者是否有許可權做一些其他操作。

2.傳統的Session 和Cookie

  • 主要用於無狀態請求下的的使用者身份識別,只不過Session將資訊儲存在伺服器端,Cookie將資訊儲存在使用者端。

Session

  • 在使用者端第一次進行存取時,伺服器端會生成一個Session id返回到使用者端

  • 使用者端將Session id儲存在本地後續每一次請求都帶上這個id

  • 伺服器端從接收到的請求中根據Session id在自己儲存的資訊中識別使用者端

Cookie

  • 在使用者端存取伺服器時,伺服器端會在響應中頒發一個Cookie

  • 使用者端會把cookie儲存,當再存取伺服器端時會將cookie和請求一併提交

  • 伺服器端會檢查cookie識別使用者端,並也可以根據需要修改cookie的內容

3.存在的問題

在分散式或叢集系統中使用Session

假設現在伺服器為了更好的承載和容災將系統做了分散式和叢集,也就是有了N個伺服器端,那是不是每一個伺服器端都要具有對每一個使用者端的Session或者Cookie的識別能力呢?

這個可以使用Session共用的方式用於Session的識別,但是這並不能解決分散式系統下依然存在這個問題,因為通常每一個分散式系統都由不同的人負責或者跨網路,甚至不同的公司,不可能全部都做session共用吧?這個時候就誕生了一個新的方式,使用Token

4.Token

  • Token是伺服器端生成的一串字串,以作使用者端進行請求的一個令牌。

執行步驟

  • 使用者向統一的鑑權授權系統發起使用者名稱和密碼的校驗

  • 校驗通過後會頒發一個Token,使用者就拿著頒發的Token去存取其他三方系統

  • 三方系統可以直接請求鑑權授權系統驗證當前Token的合法性,也可以根據對稱加密使用祕鑰解密Token以驗證合法性

.NET Core中鑑權

  • Authentication: 鑑定身份資訊,例如使用者有沒有登入,使用者基本資訊

  • Authorization: 判定使用者有沒有許可權

1.NET Core鑑權授權基本概念

在NETCORE中鑑權授權是通過AuthenticationHttpContextExtensions擴充套件類中的實現的HttpContext的擴充套件方法來完成的

 public static class AuthenticationHttpContextExtensions
 {
   public static Task SignInAsync(this HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties) 
   {
       context.RequestServices.GetRequiredService<IAuthenticationService>().SignInAsync(context, scheme, principal, properties);
   }         
 }

它真正的核心在
Microsoft.AspNetCore.Authorization模組,整個流程處理主要包含如下幾個關鍵類

  • IAuthenticationHandlerProvider

負責對使用者憑證的驗證,提供IAuthenticationHandler處理器給IAuthenticationService用於處理鑑權請求,當然可以自定義處理器

  • IAuthenticationSchemeProvider

選擇標識使用的是哪種認證方式

  • IAuthenticationService

提供鑑權統一認證的5個核心業務介面

 public interface IAuthenticationService
 {
   //查詢鑑權
   Task<AuthenticateResult> AuthenticateAsync(HttpContext context, string scheme);
 
   //登入寫入鑑權憑證
   Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties);
     
    //退出登入清理憑證
   Task SignOutAsync(HttpContext context, string scheme, AuthenticationProperties properties);
   
   Task ChallengeAsync(HttpContext context, string scheme, AuthenticationProperties properties);
   
   Task ForbidAsync(HttpContext context, string scheme, AuthenticationProperties properties);
 }

在它的實現類AuthenticationService中的SignInAsync方法
配合IAuthenticationHandlerProvider 和IAuthenticationSchemeProvider得到一個IAuthenticationHandler,最終將鑑權寫入和讀取都由它完成

public virtual async Task SignInAsync(HttpContext context, string scheme, ClaimsPrincipal principal, AuthenticationProperties properties)
{      
   if (scheme == null)
    {
        //IAuthenticationSchemeProvider範例
        var defaultScheme = await Schemes.GetDefaultSignInSchemeAsync();
        scheme = defaultScheme?.Name;
    }

  //IAuthenticationHandlerProvider範例獲取處理器
  var handler = await Handlers.GetHandlerAsync(context, scheme);
  var signInHandler = handler as IAuthenticationSignInHandler;
  
  //各自的處理器handler 
  //例如使用Cookie 就會注入一個CookieAuthenticationHandler
  //使用JWT 就注入一個JwtBearerHandler
  await signInHandler.SignInAsync(principal, properties);
}

2.使用Cookie預設流程鑑權

  • 使用中介軟體加入管道,用於找到鑑權HttpContext.AuthenticateAsync()
   //核心原始碼就是AuthenticationMiddleware中介軟體
   app.UseAuthentication();
  • 注入容器,將CookieAuthenticationHandler作為處理邏輯
services.AddAuthentication(options =>
{
     //CookieAuthenticationDefaults.AuthenticationScheme == "Cookies"
     options.DefaultAuthenticateScheme = "Cookies";
     options.DefaultSignInScheme = "Cookies";
}).AddCookie();
  • 在登入時寫入憑證
  • Claims:一項資訊,例如工牌的姓名是一個Claims ,工牌號碼也是一個Claims

  • ClaimsIdentity:一組Claims 組成的資訊,就是一個使用者身份資訊

  • ClaimsPrincipal:一個使用者有多個身份

  • AuthenticationTicket:使用者票據,用於包裹ClaimsPrincipal

    
  [AllowAnonymous]
  public async Task<IActionResult> Login(string name, string password)
  {
      if(name!="Admin" && password!="000000")
      {
         var result = new JsonResult(new{ Result = false,Message = "登入失敗"});
         return result;
      }
     //Claims  ⫋ ClaimsIdentity ⫋ ClaimsPrincipal
     var claimIdentity = new ClaimsIdentity("ClaimsIdentity");
     claimIdentity.AddClaim(new Claim(ClaimTypes.Name, name));
     claimIdentity.AddClaim(new Claim(ClaimTypes.Address, "地址資訊"));
     
     AuthenticationProperties ap = new AuthenticationProperties();
     ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(claimIdentity);
     await base.HttpContext.SignInAsync("Cookies",claimsPrincipal , ap)
     return new JsonResult(new{ Result = false,Message = "登入成功"});
  }

在其他控制器上標記[Authorize]特性,在存取介面框架會自動進行鑑權並將身份資訊寫入上下文

  • [AllowAnonymous]:匿名可存取

  • [Authorize]:必須登入才可存取

3.自定義IAuthenticationHandler

  • 實現IAuthenticationHandler, IAuthenticationSignInHandler, IAuthenticationSignOutHandler三個介面
public class CoreAuthorizationHandler : IAuthenticationHandler
,IAuthenticationSignInHandler, IAuthenticationSignOutHandler
{
      public AuthenticationScheme Scheme { get; private set; }
      protected HttpContext Context { get; private set; }
      public Task InitializeAsync(AuthenticationScheme scheme, HttpContext context)
      {
          Scheme = scheme;
          Context = context;
          return Task.CompletedTask;
      }
      
     public async Task<AuthenticateResult> AuthenticateAsync()
     {
        var cookie = Context.Request.Cookies["CustomCookie"];
        if (string.IsNullOrEmpty(cookie))
        {
            return AuthenticateResult.NoResult();
        }
        AuthenticateResult result = AuthenticateResult
        .Success(Deserialize(cookie));
        return  await Task.FromResult(result);
    }
    
     public Task ChallengeAsync(AuthenticationProperties properties)
     {
          return Task.CompletedTask;
     }

     public Task ForbidAsync(AuthenticationProperties properties)
     {
          Context.Response.StatusCode = 403;
          return Task.CompletedTask;
     }
        
         public Task SignInAsync(ClaimsPrincipal user, AuthenticationProperties properties)
        {
            var ticket = new AuthenticationTicket(user, properties, Scheme.Name);
            Context.Response.Cookies.Append("CoreAuthorizationHandlerCookies", Serialize(ticket));
            return Task.CompletedTask;
        }

     public Task SignOutAsync(AuthenticationProperties properties)
     {
            Context.Response.Cookies.Delete("CoreAuthorizationHandlerCookies");
            return Task.CompletedTask;
     }
        
     private AuthenticationTicket Deserialize(string content)
     {
         byte[] byteTicket = System.Text.Encoding.Default.GetBytes(content);
         return TicketSerializer.Default.Deserialize(byteTicket);
     }
     private string Serialize(AuthenticationTicket ticket)
     {
        //需要引入  Microsoft.AspNetCore.Authentication
        byte[] byteTicket = TicketSerializer.Default.Serialize(ticket);
        return Encoding.Default.GetString(byteTicket);
     }
}

  • 在容器中註冊自定義的Handler
services.AddAuthenticationCore(options =>
{
   options.AddScheme<CoreMvcAuthenticationHandler>("AuthenticationScheme", "AuthenticationScheme");
});

 到此這篇關於.NET CORE 鑑權的實現範例的文章就介紹到這了,更多相關.NET CORE 鑑權 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com