這難道不是.NET5 的bug? 線上求錘?

_小碼甲發表於2021-01-20

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確實包含AuthorizeAllowAnonymous兩個特性!

後續

我已經在github上提了issue(https://github.com/dotnet/aspnetcore/issues/29377), 講述了這個樸素的需求面臨的障礙,但是官方的回答我並不滿意。

暫時採用變通方案,我自行寫了一個授權中介軟體(主體拷貝自官方), 只是自行將對[AllowAnonymous]特性的檢測應用程式碼提到端點授權程式碼的前面, 這也是我內心認為的bug的修復方案。

歡迎大家留言,提出意見或看法!

相關文章