zoukankan      html  css  js  c++  java
  • 2020/01/22更新---- 这难道不是.NET5 的bug? 在线求锤?

    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-Action添加[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的修复方案。

    欢迎大家留言,提出意见或看法!

    ---2020/01/22更新-------------------------------

    之前我接收到各位大佬的留言: 不管是匿名还是鉴权访问, 均需要登记在册,再根据是MVC上否有匿名元数据(有的话,跳过),没有就继续走授权流程。

    但是我又仔细检视了源码,发现并不完全正确, 请看官仔细观察我上面的示例, 端点路由还有一个[健康检查],端点上直接加上了[AllowAnonymous]

    endpoints.MapHealthChecks("/healthz").AllowAnonymous().WithDisplayName("healthz");
    

    这个端点并没有进入认证流程,从授权中间件源码上看也是如此。

    故官方源码是否能进入认证逻辑: 关键是看能不能在端点上直接找到授权策略

    var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();   
                var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);
                if (policy == null)
                {
                    await _next(context);
                    return;
                }
    

    健康检查端点直接应用了[AllowAnonymous](实际上你可以不加), 这样就没有授权策略(policy== null),这个时候自然跳过后续,进入业务逻辑。
    甚至, 你可以这样写:

    endpoints.MapControllers().RequireAuthorization().AllowAnonymous().WithDisplayName("default");
    

    这样的代码也能进入认证逻辑,因为它包含了授权声明.

    根据以上分析,实际上端点上授权流程是这样的:

    以上给我们的结果是: 端点、MVC Controller上存在匿名访问声明时,其效果是不一样的。

    源码对端点上的授权声明(匿名.授权)的处理优先级 高于MVC Controller上的[AllowAnonymousAttribute].

    或者说端点上的全局要求授权的处理优先级高于[AllowAnonymous],总之, 有特殊代码在作怪

  • 相关阅读:
    NetSuite Batch Process Status
    NetSuite generated bank files and the Bank Reconciliation process
    Global Search file content in Gitlab repositories, search across repositories, search across all files
    FedEx Package Rate Integration with NetSuite direct integrate by WebServices
    git Merge branches
    git tag and NetSuite deployment tracking
    API 读写cookie的方法
    C# 生成缩略图
    解决jquery操作checkbox全选全不选无法勾选问题
    JS读取写入删除Cookie方法
  • 原文地址:https://www.cnblogs.com/JulianHuang/p/14298737.html
Copyright © 2011-2022 走看看