深刻解讀 ASP.NET Core 身份認證過程

長話短說:上文咱們講了 ASP.NET Core 基於聲明的訪問控制究竟是什麼鬼?
今天咱們乘勝追擊:聊一聊ASP.NET Core 中的身份驗證。html

身份驗證是肯定用戶身份的過程。 受權是肯定用戶是否有權訪問資源的過程。瀏覽器

1. 萬變不離其宗

顯而易見,一個常規的身份認證用例包括兩部分:
① 對用戶進行身份驗證
② 在未經身份驗證的用戶試圖訪問受限資源時做出反應cookie

已註冊的身份驗證處理程序及其配置選項被稱爲「方案」,方案可用做一種機制,供用戶參考相關處理程序的身份驗證、挑戰和禁止行爲。框架

咱們口頭上常說的:
基於cookie認證方案,若認證成功,go on,若認證失敗則跳轉回登陸頁面;
基於基自己份認證(BA)方案,若認證成功,go on,若認證失敗則給瀏覽器返回WWW-Authenticate標頭, 瀏覽器會再次彈出認證窗口。ide

2. ASP.NET Core認證原理

在 ASP.NET Core 中,身份驗證由IAuthenticationService負責,身份驗證服務會調用已註冊的身份驗證處理程序來完成與身份驗證相關的操做, 整個驗證過程由認證中間件來串聯。函數

一圖以蔽之:
ui

其中有幾個關鍵步驟this

  1. 認證處理程序
    可結合方案Scheme中的配置項AuthenticationSchemeOptions編寫認證處理程序。code

    基於Cookie的認證方案可在Options項中可指定登陸地址,
    基於基自己份的認證方案可在Options項中指定用戶名/密碼;htm

  2. 身份認證程序繼承自AuthenticationHandler類IAuthenticationHandler接口

  • 核心認證函數可落地基於聲明的訪問控制,生成綁定了ClaimsPrincipal、Scheme的AuthenticationTicket對象; 不管認證成功/失敗,函數返回AuthenticateResult對象

  • 挑戰(對未認證的用戶作出的反應): 例如返回登陸頁面

  • 禁止(對已認證,但對特定資源無權訪問作出的反應) : 例如返回提示字符串

以上均爲服務註冊過程

  1. 收到請求,認證中間件使用IAuthenticationService對HttpContext按照要求的scheme進行認證, 實際內部會調用第2步編寫的認證處理程序。

以上認證原理,以前有一個近身實戰: ASP.NET Core 實現基自己份驗證。
源代碼以下: http://www.javashuo.com/article/p-cejrdwqr-z.html

3. ASP.NET Core獲取當前用戶

基於聲明的訪問控制, 咱們會在HttpContext.User屬性存儲身份信息。

var claims = new[] {
               new Claim(ClaimTypes.NameIdentifier,username),
               new Claim(ClaimTypes.Name,username),
           };
 var identity = new ClaimsIdentity(claims, Scheme.Name);
 var principal = new ClaimsPrincipal(identity);
 Context.User = principal;

Web應用程序中獲取當前登陸用戶, 有兩種代碼場合:

3.1 在控制器中獲取當前登陸用戶

控制器是處理請求的 一等公民,天生自帶HttpContext。
直接經過ControllerBase基類中包含的HttpContext屬性,獲取User對象。

實際上Razor Page、Razor View、Middleware均包含HttpContext屬性/參數, 可直接使用。

3.2 在服務中獲取當前登陸用戶

這個時候,服務是做爲請求處理中的一個環節,並無直接可用的HttpContext。
ASP.NET Core 提供了IHttpContextAccessor類可以注入這次請求中的HttpContext對象(依賴注入框架的做用)。

//  下面的用戶實體類,須要獲取當前登陸用戶,藉助IHttpContextAccessor注入httpContext
public class UserEntityService : IUserEntityService
{
   private IHttpContextAccessor _accessor;
   private readonly IMongoCollection<UserProfile> _users;

   public UserEntityService(IHttpContextAccessor accessor, IDefaultMongoDatabaseProvider databaseProvider)
   {
       _accessor = accessor;
       _users = databaseProvider.GetCollection<UserProfile>(CollectionNames.UserProfiles);
   }

   public Task<UserProfile> GetCurrentUserAsync()
   {
       var rawUser = this._accessor.HttpContext.User();
       if (rawUser == null)
       {
          return null;
       }
       var filter = Builders<UserProfile>.Filter.Eq("UserId", rawUser.UserId);
      return _users.Find(filter).FirstOrDefaultAsync();
   }
}

+ abp vnext

咱們不須要區分以上代碼場合,在Controller或者Application 服務中使用ICurrentUser接口拿到登陸用戶。

旁白

我的認爲,ASP.NET Core身份認證的源代碼, 基於現實認知提煉而來,讓咱們驚歎於框架代碼的的簡潔精煉、井井有條。

基於聲明的訪問控制已成標準,ASP.NET Core/abp vnext 均提供了完善的支持。

相關文章
相關標籤/搜索