• asp.net core 授权(1)


    IAuthorizeDate接口代表了授权系统的源头:

    public interface IAuthorizeData
    {
        string Policy { get; set; }
        string Roles { get; set; }
        string AuthenticationSchemes { get; set; }
    }

    接口中定义的三个属性分别代表了三种授权类型:

    1、基于角色的授权:

    [Authorize(Roles = "Admin")] // 多个Role可以使用,分割
    public class SampleDataController : Controller
    {
        ...
    }

    2、基于scheme的授权:

    [Authorize(AuthenticationSchemes = "Cookies")] // 多个Scheme可以使用,分割
    public class SampleDataController : Controller
    {
        ...
    }

    3、基于策略的授权:

    [Authorize(Policy = "EmployeeOnly")]
    public class SampleDataController : Controller
    {
        
    }

    基于策略的授权是授权的核心,使用这种授权策略时,首先要定义策略:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
    
        services.AddAuthorization(options =>
        {
            options.AddPolicy("EmployeeOnly", policy => policy.RequireClaim("EmployeeNumber"));
        });
    }

    授权策略本质上就是对claims的一系列断言。

    而基于角色和基于scheme的授权都是一种语法糖,最终会转换为策略授权。

    详解

    整个asp.net core的授权配置通过一个AddAuthorization来进行的:

    public static IServiceCollection AddAuthorization(
          this IServiceCollection services,
          Action<AuthorizationOptions> configure)
        {
          if (services == null)
            throw new ArgumentNullException(nameof (services));
          services.AddAuthorizationCore(configure);
          services.AddAuthorizationPolicyEvaluator();
          return services;
        }
    public static IServiceCollection AddAuthorization(
          this IServiceCollection services,
          Action<AuthorizationOptions> configure)
        {
          if (services == null)
            throw new ArgumentNullException(nameof (services));
          services.AddAuthorizationCore(configure);
          services.AddAuthorizationPolicyEvaluator();
          return services;
        }
    public static IServiceCollection AddAuthorizationCore(
          this IServiceCollection services,
          Action<AuthorizationOptions> configure)
        {
          if (services == null)
            throw new ArgumentNullException(nameof (services));
          if (configure != null)
            services.Configure<AuthorizationOptions>(configure);
          return services.AddAuthorizationCore();
        }
    public static IServiceCollection AddAuthorizationCore(
    this IServiceCollection services)
    {
    if (services == null)
    throw new ArgumentNullException(nameof (services));
    services.TryAdd(ServiceDescriptor.Transient<IAuthorizationService, DefaultAuthorizationService>());
    services.TryAdd(ServiceDescriptor.Transient<IAuthorizationPolicyProvider, DefaultAuthorizationPolicyProvider>());
    services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerProvider, DefaultAuthorizationHandlerProvider>());
    services.TryAdd(ServiceDescriptor.Transient<IAuthorizationEvaluator, DefaultAuthorizationEvaluator>());
    services.TryAdd(ServiceDescriptor.Transient<IAuthorizationHandlerContextFactory, DefaultAuthorizationHandlerContextFactory>());
    services.TryAddEnumerable(ServiceDescriptor.Transient<IAuthorizationHandler, PassThroughAuthorizationHandler>());
    return services;
    }
     
     public static IServiceCollection AddAuthorizationPolicyEvaluator(
          this IServiceCollection services)
        {
          if (services == null)
            throw new ArgumentNullException(nameof (services));
          services.TryAddSingleton<AuthorizationPolicyMarkerService>();
          services.TryAdd(ServiceDescriptor.Transient<IPolicyEvaluator, PolicyEvaluator>());
          return services;
        }

    AuthorizationOptions

    典型的Options模式,设置和获取授权策略的入口点

    public class AuthorizationOptions
      {
        private IDictionary<string, AuthorizationPolicy> PolicyMap { get; } = (IDictionary<string, AuthorizationPolicy>) new Dictionary<string, AuthorizationPolicy>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
    
        public bool InvokeHandlersAfterFailure { get; set; } = true;
    
        public AuthorizationPolicy DefaultPolicy { get; set; } = new AuthorizationPolicyBuilder(Array.Empty<string>()).RequireAuthenticatedUser().Build();
    
        public AuthorizationPolicy FallbackPolicy { get; set; }
    
        public void AddPolicy(string name, AuthorizationPolicy policy)
        {
          if (name == null)
            throw new ArgumentNullException(nameof (name));
          if (policy == null)
            throw new ArgumentNullException(nameof (policy));
          this.PolicyMap[name] = policy;
        }
    
        public void AddPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy)
        {
          if (name == null)
            throw new ArgumentNullException(nameof (name));
          if (configurePolicy == null)
            throw new ArgumentNullException(nameof (configurePolicy));
          AuthorizationPolicyBuilder authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
          configurePolicy(authorizationPolicyBuilder);
          this.PolicyMap[name] = authorizationPolicyBuilder.Build();
        }
    
        public AuthorizationPolicy GetPolicy(string name)
        {
          if (name == null)
            throw new ArgumentNullException(nameof (name));
          return !this.PolicyMap.ContainsKey(name) ? (AuthorizationPolicy) null : this.PolicyMap[name];
        }
      }

    这个类中的几个重要的属性和方法:

    1、PolicyMap,类型为IDictionary<string, AuthorizationPolicy>,维护一个授权策略的字典。

    2、DefaultPolicy ,类型为AuthorizationPolicy,这个默认的策略要求用户必须登录

    3、FallbackPolicy ,类型为AuthorizationPolicy,这个用来作为后备的授权策略

    4、AddPolicy(),用来维护PolicyMap

    5、GetPolicy(),用来根据名称获取相应的Policy,获取不到会返回null

    综上,AuthorizationOptions就是用来设置和获取授权策略的。

    AuthorizationPolicy

    表示一个授权策略

    public class AuthorizationPolicy
      {
        public AuthorizationPolicy(
          IEnumerable<IAuthorizationRequirement> requirements,
          IEnumerable<string> authenticationSchemes)
        {
          if (requirements == null)
            throw new ArgumentNullException(nameof (requirements));
          if (authenticationSchemes == null)
            throw new ArgumentNullException(nameof (authenticationSchemes));
          if (requirements.Count<IAuthorizationRequirement>() == 0)
            throw new InvalidOperationException(Resources.Exception_AuthorizationPolicyEmpty);
          this.Requirements = (IReadOnlyList<IAuthorizationRequirement>) new List<IAuthorizationRequirement>(requirements).AsReadOnly();
          this.AuthenticationSchemes = (IReadOnlyList<string>) new List<string>(authenticationSchemes).AsReadOnly();
        }
    
        public IReadOnlyList<IAuthorizationRequirement> Requirements { get; }
    
        public IReadOnlyList<string> AuthenticationSchemes { get; }
    
        public static AuthorizationPolicy Combine(
          params AuthorizationPolicy[] policies)
        {
          if (policies == null)
            throw new ArgumentNullException(nameof (policies));
          return AuthorizationPolicy.Combine((IEnumerable<AuthorizationPolicy>) policies);
        }
    
        public static AuthorizationPolicy Combine(
          IEnumerable<AuthorizationPolicy> policies)
        {
          if (policies == null)
            throw new ArgumentNullException(nameof (policies));
          AuthorizationPolicyBuilder authorizationPolicyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
          foreach (AuthorizationPolicy policy in policies)
            authorizationPolicyBuilder.Combine(policy);
          return authorizationPolicyBuilder.Build();
        }
    
        public static async Task<AuthorizationPolicy> CombineAsync(
          IAuthorizationPolicyProvider policyProvider,
          IEnumerable<IAuthorizeData> authorizeData)
        {
          if (policyProvider == null)
            throw new ArgumentNullException(nameof (policyProvider));
          if (authorizeData == null)
            throw new ArgumentNullException(nameof (authorizeData));
          bool flag1 = false;
          if (authorizeData is IList<IAuthorizeData> authorizeDataList)
            flag1 = authorizeDataList.Count == 0;
          AuthorizationPolicyBuilder policyBuilder = (AuthorizationPolicyBuilder) null;
          if (!flag1)
          {
            foreach (IAuthorizeData authorizeData1 in authorizeData)
            {
              IAuthorizeData authorizeDatum = authorizeData1;
              if (policyBuilder == null)
                policyBuilder = new AuthorizationPolicyBuilder(Array.Empty<string>());
    //Avoid allocating enumerator if the data is known to be empty
    bool flag2 = true; if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy)) { AuthorizationPolicy policyAsync = await policyProvider.GetPolicyAsync(authorizeDatum.Policy); if (policyAsync == null) throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound((object) authorizeDatum.Policy)); policyBuilder.Combine(policyAsync); flag2 = false; } string[] strArray1 = authorizeDatum.Roles?.Split(',', StringSplitOptions.None); if (strArray1 != null && ((IEnumerable<string>) strArray1).Any<string>()) { policyBuilder.RequireRole(((IEnumerable<string>) strArray1).Where<string>((Func<string, bool>) (r => !string.IsNullOrWhiteSpace(r))).Select<string, string>((Func<string, string>) (r => r.Trim()))); flag2 = false; } string[] strArray2 = authorizeDatum.AuthenticationSchemes?.Split(',', StringSplitOptions.None); if (strArray2 != null && ((IEnumerable<string>) strArray2).Any<string>()) { foreach (string str in strArray2) { if (!string.IsNullOrWhiteSpace(str)) policyBuilder.AuthenticationSchemes.Add(str.Trim()); } } if (flag2) { AuthorizationPolicyBuilder authorizationPolicyBuilder = policyBuilder; authorizationPolicyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync()); authorizationPolicyBuilder = (AuthorizationPolicyBuilder) null; } authorizeDatum = (IAuthorizeData) null; } } if (policyBuilder == null) { AuthorizationPolicy fallbackPolicyAsync = await policyProvider.GetFallbackPolicyAsync(); if (fallbackPolicyAsync != null) return fallbackPolicyAsync; } return policyBuilder?.Build(); } }

    AuthorizationPolicy维护了两个只读的列表,一个是IAuthorizationRequirement的,另一个是string类型的,表示AuthenticationSchemes。又两个方法,一个是Combine(),这个方法是直接通过AuthorizePolicyBuilder来build的,还有一个CombineAsync方法,则是将我们上面介绍的IAuthorizeData转换成AuthorizePolicy,所以说,基于角色的授权和基于方案(AuthenticationScheme)的授权都会转换成基于策略的授权。

    CombineAsync方法执行流程如下:

    1、对传入的参数(IAuthorizationPolicyProvider 和IEnumerable<IAuthorizeData>)进行断言,不能为空,否则抛出异常。

    2、声明一个布尔类型变量(上面是flag1),表示如果已知数据(IEnumerable<IAuthorizeData>)为空,则避免分配枚举数(Avoid allocating enumerator if the data is known to be empty),这个值的设置方式为对传入的authorizeData参数进行校验,首先判断是否为IList<T>,然后判断它的Count属性是否等于0。两者都为true则这个布尔值为true。

    3、对第二步声明的这个布尔值进行判断,如果为false,那么进入方法体:

          ①对传入的authorizeData进行迭代,迭代方法内部做如下处理:

           ①-①初始化一个AuthorizationPolicyBuilder,声明一个布尔变量(flag2),默认值为true,这个变量表示是否使用默认的授权策略(useDefaultPolicy)。

           ①-②判断每一个迭代变量(authorizeDatum),如果Policy属性不为空,那么进入方法体,利用传入的policyProvider的GetPolicyAsync()方法,将authorizeDatum的Policy作为参数传入拿到一个AuthorizePolicy并赋值给一 个policyAsync变量。如果这个policyAsync为空,那么就抛出异常。如果不为空,那么利用①-①初始化的这个AuthorizePolicyBuilder来Combine这个获取到的policyAsync。然后将①-①中声明的flag2设置为false。这两步就将authorizeDatum这个迭代变量中的Policy情况处理完了。

          ①-③继续处理authorizeDatum中的roles,还是利用AuthorizationPolicyBuilder的RequireRoles将这个IAuthorizeData接口中的Roles处理

          ①-④继续处理authorizeDatum中的AuthenticationSchemes,同样利用AuthorizationPolicyBuilder将这个IAuthorizeData接口中的AuthenticationSchemes处理

          ①-⑤判断在①-①中声明的flag2,如果这个布尔值还是True,那么就用①-①中声明的AuthorizationPolicyBuilder来初始化一个默认的AuthorizationPolicy,这个默认的AuthorizationPolicy就是一个查看用户是否认证过的policy。至于这个flag2标记,会在检查过每一个迭代变量authorizeDatum的policy和roles之后进行相应的设置,如果authorizeDatum的policy和roles都没有,那么这个值就保持为true,反之会被设置为false。

          至此都是CombineAsync这个方法传入的这个authorizeData参数有值的情况下,如果传入的authorizeData没有值,那么从传入的policyProvider参数中拿到一个FallBackPolicy,由于policyProvider依赖于AuthorizatoinOptions,所以对PolicyProvider进行的操作基本都是对AuthorizationOptions的操作。

          总结:AuthorizationPolicyBuilder在Build方法执行前一直在维护两个关键的属性:

    public IList<IAuthorizationRequirement> Requirements { get; set; } = (IList<IAuthorizationRequirement>) new List<IAuthorizationRequirement>();
    
    public IList<string> AuthenticationSchemes { get; set; } = (IList<string>) new List<string>();

    这两个属性也是IAuthorizationPolicy中的两个属性,AuthorizationPolicyBuilder装配一个AuthorizationPolicy的方式有三种,一个是Combine(),这个是将传入的一个Policy进行拆解,将它里面的这两个属性添加到AuthorizationPolicyBuilder中,一个是各种RequireXXXX方法体现出来的,最终都是创建一个IAuthorizationRequirment,添加在自身的Requirements属性中,还有一个是AddAuthenticationSchemes(),将 代表scheme的字符串添加到自身的AuthenticationSchemes属性中,当Build方法执行时,直接新建一个AuthorizationPolicy,将自身维护的这两个属性传入AuthorizationPolicy的构造函数中。

     

  • 相关阅读:
    ubuntu下安装jupyter notebook问题。ERROR: Package ‘ipython‘ requires a different Python: 3.5.2 not in 」=3.6
    VmWare虚拟机设置ubuntu和windows之间的共享文件夹
    标准测试宏选项
    C库函数、系统函数等调用错误的处理方法
    比atoi()函数更健壮的一类包装函数
    系统函数和C库函数调用的几种错误处理方法
    经典生产者-消费者问题解析
    linux下的并发编程详解
    一文学会GDB操作命令
    Stm32CubeMx lwip+freeRTOS TCP 服务
  • 原文地址:https://www.cnblogs.com/pangjianxin/p/12217123.html
Copyright © 2020-2023  润新知