hello,最近在對一個使用.NET5專案的認證授權系統進行重構,對.NET 5的授權中介軟體的原始碼有些看法。
也希望同學們能幫我理解。
一個樸素的需求
這是一個api專案,預設所有的api都需要授權, 少數散落在Controller各處的api不需要授權訪問,故這裡有個全域性授權訪問+特例匿名訪問的矛盾。
以我粗鄙的想法,我相信.NET會很好的處理好這個矛盾: [AllowAnonymous]優先。
這個想法在https://docs.microsoft.com/en-us/aspnet/core/security/authorization/simple?view=aspnetcore-5.0 得到印證。
需求實現
在Startup ConfigureServices新增認證、授權服務
// 認證服務
services.AddAuthentication("token")
.AddScheme<TokenAuthenticationOptions, TokenAuthenticationHandler>(TokenAuthenticationDefaults.AuthenticationScheme,
option => {
option.ClaimsIssuer = configuration.GetSection("AppKeys")["ClaimsIssuer"].ToString();
option.ClientId = configuration.GetSection("AppKeys")["ClientId"].ToString();
option.ClientSign = configuration.GetSection("AppKeys")["ClientSign"].ToString();
});
// 授權服務
services.AddAuthorization(options =>{
// 預設策略
options.DefaultPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.AddAuthenticationSchemes("token")
.Build();
});
既然現在.NET5推薦使用端點路由的形式,故針對我這個樸素的需求:
我理所當然會嘗試使用在Controller端點上要求全域性授權訪問,對散落在各地的不需要授權的Controller新增[AllowAnonymous]特性。
// 註冊授權中介軟體
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/healthz").AllowAnonymous().WithDisplayName("healthz");
// 全域性對所有api要求授權訪問
endpoints.MapControllers().RequireAuthorization().WithDisplayName("default");
});
[AllowAnonymous]
[HttpGet]
[Route("triggerorder")]
public void TriggerOrder()
{
...
}
實際測試發現,雖然我對Controller標記了允許匿名訪問, 但請求始終進入了授權認證過程!
這個樸素的授權需求竟然還遇到了障礙。
探究原始碼
授權中介軟體原始碼在此: https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authorization/Policy/src/AuthorizationMiddleware.cs
原始碼很簡單:
1..NET 授權中介軟體先從端點獲取了全域性授權宣告IAuthorizeData
2. 通過這個宣告拿到了詳細的全域性授權策略
3. 後面直接開始走授權認證過程, ??? 難以理解
4. 雖然後面又開始檢測Controller-Action上面的AllowAnonymous
特性,這時候已經晚了,你都把授權認證流程都走一遍了!!
很明顯,基於端點的全域性授權+零散的匿名訪問特性 並沒有貫徹[AllowAnonymous]特性優先的原則。
在這個測試例子中,當前端點的
metadata
確實包含Authorize
和AllowAnonymous
兩個特性!
後續
我已經在github上提了issue(https://github.com/dotnet/aspnetcore/issues/29377), 講述了這個樸素的需求面臨的障礙,但是官方的回答我並不滿意。
暫時採用變通方案,我自行寫了一個授權中介軟體(主體拷貝自官方), 只是自行將對[AllowAnonymous]特性的檢測應用程式碼提到端點授權程式碼的前面, 這也是我內心認為的bug的修復方案。
歡迎大家留言,提出意見或看法!