注冊服務、配置選項、添加身份驗證方案
在Startup.ConfigureServices執行services.AddAuthentication()
注冊如下服務(便於理解省略了部分輔助服務):
- services.TryAddScoped<IAuthenticationService, AuthenticationService>();
- services.TryAddScoped<IAuthenticationHandlerProvider, AuthenticationHandlerProvider>();
- services.TryAddSingleton<IAuthenticationSchemeProvider, AuthenticationSchemeProvider>();
整個應用的身份驗證有個選項對象叫AuthenticationOptions(上一篇有描述),允許我們對身份驗證做整體配置,這個配置主要體現為:配置系統需要支持的身份驗證方案列表;指定默認身份驗證方案、默認登錄時用的身份驗證方案...默認注銷...等。這個對象的應用使用asp.net core的選項模型,我們可以通過AddAuthentication(Action<AuthenticationOptions>)重載來進行配置。參考如下代碼:
1 services.AddAuthentication(authenticationOptions=> { 2 authenticationOptions.AddScheme<CookieAuthenticationHandler>("cookie", "顯示名cookie"); 3 authenticationOptions.AddScheme<JwtBearerHandler>("jwt","顯示名jwtToken"); 4 authenticationOptions.DefaultAuthenticateScheme = "cookie"; 5 //...其它配置 6 });
此重載同樣會先注冊上面的核心服務。然后設置初始化AuthenticationOptions的委托,當某個類注入AuthenticationOptions時,依賴注入框架會調用此委托來初始化這個選項對象。
另一個重載AddAuthentication(string defaultScheme)內部也是調用上面的方法,只是只設置了AuthenticationOptions.DefaultScheme
AddAuthentication方法始終返回AuthenticationBuilder,它允許我們通過鏈式調用方式來向AuthenticationOptions添加多個身份驗證方案,所以更常見的方式如下:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie().AddJwtBearer();
CookieAuthenticationDefaults.AuthenticationScheme常來指明將哪個身份驗證方案作為默認。后續分別添加了cookie和JwtBearer兩個身份驗證方案。
我們說AuthenticationOptions是針對整個應用程序的身份驗證選項,可以簡單理解為它是身份驗證方案的配置時容器。針對特定身份驗證方案也有自己的配置對象。以AddCookie()為例,它等同於:
1 authenticationOptions.AddScheme<CookieAuthenticationHandler>(CookieAuthenticationDefaults.AuthenticationScheme, "顯示名cookie",); 2 service.Configre<CookieAuthenticationOptions>(options=>{ 4 options.Cookie.Name = CookieAuthenticationDefaults.CookiePrefix + name; 6 options.CookieManager = new ChunkingCookieManager(); 7 options.LoginPath = CookieAuthenticationDefaults.LoginPath; 8 options.LogoutPath = CookieAuthenticationDefaults.LogoutPath; 9 options.AccessDeniedPath = CookieAuthenticationDefaults.AccessDeniedPath; 10 } 11 });
CookieAuthenticationOptions就是針對這個cookie身份驗證方案的選項對象,將來某個類注入此選項對象時,依賴注入框架會回調此委托來初始化它。參考:選項模型。當然AddCookie有對應的重載允許我們自己的委托來初始化這個選項對象。類似下面的代碼:
1 services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie("換個方案名","顯示名",opt=> { 2 opt.SlidingExpiration = true;//滑動過期? 3 //設置其它跟cookie身份驗證相關的東東... 4 }).AddJwtBearer();
現在看看這段代碼就親切多了。
身份驗證方案運行時容器AuthenticationSchemeProvider的建立
由於AuthenticationSchemeProvider是以單例形式注冊到依賴注入容器中的,因此應該在注冊時(不是很確定,假設吧)就會創建AuthenticationSchemeProvider,它通的構造函數定義了IOptions<AuthenticationOptions>參數,上面說了AuthenticationOptions就包含上面注冊進去的身份驗證方案列表,AuthenticationSchemeProvider在構造函數中遍歷,將所有注冊的身份驗證方案存儲到自身的 IDictionary<string, AuthenticationScheme> _schemes 變量中
插入身份驗證中間件
上面只是注冊了身份驗證過程中需要的服務並配置了應用需要支持身份驗證方案列表,在將來請求抵達時需要一個中間件來處理身份驗證,核心任務是找到默認身份驗證處理器,通過它從請求中獲得當前用戶標識,然后設置到httpContext.User屬性上,至於處理的具體過程將在下一篇基於cookie的身份驗證整體流程詳細說。在Startup.Configre中通過擴展方法注冊:
app.UseRouting();
app.UseAuthentication();
app.UseEndpoints(endpoints =>{
endpoints.MapRazorPages();
});
至於為啥身份驗證中間件一定要在 app.UseRouting(); 之后,我是真的想不通....