认证授权方案之授权揭秘 (上篇)

一、前言

回顾:认证授权方案之授权初识

从上一节中,我们在对授权系统已经有了初步的认识和使用,可以发现,asp.net core为我们提供的授权策略是一个非常强大丰富且灵活的认证授权方案,能够满足大部分的授权场景。

在ConfigureServices中配置服务:将授权服务添加到容器

    public void ConfigureServices(IServiceCollection services){services.AddAuthorization(options =>{options.AddPolicy("customizePermisson",policy => policy.Requirements.Add(new PermissionRequirement("user")));});//此外,还需要在 IAuthorizationHandler 类型的范围内向 DI 系统注册新的处理程序:services.AddScoped<IAuthorizationHandler, PermissionRequirementHandler>();}

在Configure中注册管道:运行使用调用方法来配置Http请求管道

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env){    //开启授权app.UseAuthorization();}

通过以上几行代码的实现,就可以进行授权了,这个时候,你可以会问,这几行代码都进行了什么操作实现授权的?

好了,继续回到上节最后说的在这一节中对授权策略的核心进行一步步的揭秘的。

二、开始

引入整体结构

2.1  添加授权AddAuthorization

添加授权策略服务使用AddAuthorization方法,以便调用。

从源码可以发现,从core3.0后,由之前在core2.0中的AuthorizationServiceCollectionExtensions.cs文件中,原来的AddAuthorization的方法变为了AddAuthorizationCore方法,微软在这一块进行了封装在PolicyServiceCollectionExtensions.cs文件中,沿用了之前AddAuthorization拓展名称,不影响之前版本的使用。

我们来看看aspnetcore源码:

    public static class PolicyServiceCollectionExtensions{public static IServiceCollection AddAuthorizationPolicyEvaluator(this IServiceCollection services){if (services == null){throw new ArgumentNullException(nameof(services));}services.TryAddSingleton<AuthorizationPolicyMarkerService>();services.TryAddTransient<IPolicyEvaluator, PolicyEvaluator>();services.TryAddTransient<IAuthorizationMiddlewareResultHandler, AuthorizationMiddlewareResultHandler>();return services;}public static IServiceCollection AddAuthorization(this IServiceCollection services){if (services == null){throw new ArgumentNullException(nameof(services));}services.AddAuthorizationCore();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 class AuthorizationServiceCollectionExtensions{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 AddAuthorizationCore(this IServiceCollection services, Action<AuthorizationOptions> configure){if (services == null){throw new ArgumentNullException(nameof(services));}services.Configure(configure);return services.AddAuthorizationCore();}}

由上可知,在调用AddAuthorization方法进行授权配置的时候,需要使用到AuthorizationOptions委托方式传参。

所以我们再来看看下面这一行代码,通过AddPolicy实现添加策略方式。

   options.AddPolicy("customizePermisson",policy => policy.Requirements.Add(new PermissionRequirement("user")));

查看源码发现是引用了AuthorizationOptions对象。

2.2   配置选项AuthorizationOptions

授权选项实现添加和授权配置,提供授权服务的配置。

源码如下:

    public class AuthorizationOptions{private Dictionary<string, AuthorizationPolicy> PolicyMap { get; } = new Dictionary<string, AuthorizationPolicy>(StringComparer.OrdinalIgnoreCase);public bool InvokeHandlersAfterFailure { get; set; } = true;public AuthorizationPolicy DefaultPolicy { get; set; } = new AuthorizationPolicyBuilder().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));}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));}var policyBuilder = new AuthorizationPolicyBuilder();configurePolicy(policyBuilder);PolicyMap[name] = policyBuilder.Build();}public AuthorizationPolicy GetPolicy(string name){if (name == null){throw new ArgumentNullException(nameof(name));}if (PolicyMap.TryGetValue(name, out var value)){return value;}return null;}}

定义一个字典

private Dictionary<string, AuthorizationPolicy> PolicyMap { get; } = new Dictionary<string, AuthorizationPolicy>(StringComparer.OrdinalIgnoreCase);

目的在于将定义的授权策略方式都保存在这个声明的PolicyMap当中,而其中AddPolicy方法是将配置的策略添加到字典中。

public void AddPolicy(string name, AuthorizationPolicy policy);
public void AddPolicy(string name, Action<AuthorizationPolicyBuilder> configurePolicy);

而这方法中涉及到两种不同的传参对象AuthorizationPolicyAuthorizationPolicyBuilder

2.3  授权策略 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() == 0){throw new InvalidOperationException(Resources.Exception_AuthorizationPolicyEmpty);}Requirements = new List<IAuthorizationRequirement>(requirements).AsReadOnly();AuthenticationSchemes = 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 Combine((IEnumerable<AuthorizationPolicy>)policies);}public static AuthorizationPolicy Combine(IEnumerable<AuthorizationPolicy> policies){if (policies == null){throw new ArgumentNullException(nameof(policies));}var builder = new AuthorizationPolicyBuilder();foreach (var policy in policies){builder.Combine(policy);}return builder.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));}// Avoid allocating enumerator if the data is known to be emptyvar skipEnumeratingData = false;if (authorizeData is IList<IAuthorizeData> dataList){skipEnumeratingData = dataList.Count == 0;}AuthorizationPolicyBuilder policyBuilder = null;if (!skipEnumeratingData){foreach (var authorizeDatum in authorizeData){if (policyBuilder == null){policyBuilder = new AuthorizationPolicyBuilder();}var useDefaultPolicy = true;if (!string.IsNullOrWhiteSpace(authorizeDatum.Policy)){var policy = await policyProvider.GetPolicyAsync(authorizeDatum.Policy);if (policy == null){throw new InvalidOperationException(Resources.FormatException_AuthorizationPolicyNotFound(authorizeDatum.Policy));}policyBuilder.Combine(policy);useDefaultPolicy = false;}var rolesSplit = authorizeDatum.Roles?.Split(',');if (rolesSplit != null && rolesSplit.Any()){var trimmedRolesSplit = rolesSplit.Where(r => !string.IsNullOrWhiteSpace(r)).Select(r => r.Trim());policyBuilder.RequireRole(trimmedRolesSplit);useDefaultPolicy = false;}var authTypesSplit = authorizeDatum.AuthenticationSchemes?.Split(',');if (authTypesSplit != null && authTypesSplit.Any()){foreach (var authType in authTypesSplit){if (!string.IsNullOrWhiteSpace(authType)){policyBuilder.AuthenticationSchemes.Add(authType.Trim());}}}if (useDefaultPolicy){policyBuilder.Combine(await policyProvider.GetDefaultPolicyAsync());}}}// If we have no policy by now, use the fallback policy if we have oneif (policyBuilder == null){var fallbackPolicy = await policyProvider.GetFallbackPolicyAsync();if (fallbackPolicy != null){return fallbackPolicy;}}return policyBuilder?.Build();}
}

我们从源码中可以发现,Authorization 对象 Combine方法目的在于将授权策略进行合并,同时调用了AuthorizationPolicyBuilder对象中Combine方法,对授权方案或者授权策略进行合并。再来看看AuthorizationPolicy对象中的CombineAsync方法,这里的参数用到了IAuthorizeData,同时这个方法的过程是将可能基于角色,基于方案或者基于策略都合并转换为是授权策略的方式,也是通过调用AuthorizationPolicyBuilder对象来实现合并。所以可以看得出AuthorizationPolicyBuilder提供了一些创建AuthorizationPolicy的方法。

这个时候,我们可以发现,其实之前说的基于角色、基于方案的授权方式本质上来说都是基于策略授权。

2.4  构建策略AuthorizationPolicyBuilder

除了上面说到使用AuthorizationPolicy对象之外,我们还可以用AuthorizationPolicyBuilder对象以Buider来创建AuthorizationPolicy对象,将多个AuthorizationPolicy对象提供的数组进行合并,所以AuthorizationPolicyBuilder提供的Combine方法的使用,为AuthorizationPolicy授权构建提供了许多便捷的方式。

public class AuthorizationPolicyBuilder
{public AuthorizationPolicyBuilder(params string[] authenticationSchemes){AddAuthenticationSchemes(authenticationSchemes);}public AuthorizationPolicyBuilder(AuthorizationPolicy policy){Combine(policy);}public IList<IAuthorizationRequirement> Requirements { get; set; } = new List<IAuthorizationRequirement>();    public IList<string> AuthenticationSchemes { get; set; } = new List<string>();public AuthorizationPolicyBuilder AddAuthenticationSchemes(params string[] schemes){foreach (var authType in schemes){AuthenticationSchemes.Add(authType);}return this;}    public AuthorizationPolicyBuilder AddRequirements(params IAuthorizationRequirement[] requirements){foreach (var req in requirements){Requirements.Add(req);}return this;}public AuthorizationPolicyBuilder Combine(AuthorizationPolicy policy){if (policy == null){throw new ArgumentNullException(nameof(policy));}AddAuthenticationSchemes(policy.AuthenticationSchemes.ToArray());AddRequirements(policy.Requirements.ToArray());return this;}    public AuthorizationPolicyBuilder RequireClaim(string claimType, params string[] allowedValues){if (claimType == null){throw new ArgumentNullException(nameof(claimType));}return RequireClaim(claimType, (IEnumerable<string>)allowedValues);}public AuthorizationPolicyBuilder RequireClaim(string claimType, IEnumerable<string> allowedValues){if (claimType == null){throw new ArgumentNullException(nameof(claimType));}Requirements.Add(new ClaimsAuthorizationRequirement(claimType, allowedValues));return this;}    public AuthorizationPolicyBuilder RequireClaim(string claimType){if (claimType == null){throw new ArgumentNullException(nameof(claimType));}Requirements.Add(new ClaimsAuthorizationRequirement(claimType, allowedValues: null));return this;}    public AuthorizationPolicyBuilder RequireRole(params string[] roles){if (roles == null){throw new ArgumentNullException(nameof(roles));}return RequireRole((IEnumerable<string>)roles);}  public AuthorizationPolicyBuilder RequireRole(IEnumerable<string> roles){if (roles == null){throw new ArgumentNullException(nameof(roles));}Requirements.Add(new RolesAuthorizationRequirement(roles));return this;}    public AuthorizationPolicyBuilder RequireUserName(string userName){if (userName == null){throw new ArgumentNullException(nameof(userName));}Requirements.Add(new NameAuthorizationRequirement(userName));return this;}public AuthorizationPolicyBuilder RequireAuthenticatedUser(){Requirements.Add(new DenyAnonymousAuthorizationRequirement());return this;}public AuthorizationPolicyBuilder RequireAssertion(Func<AuthorizationHandlerContext, bool> handler){if (handler == null){throw new ArgumentNullException(nameof(handler));}Requirements.Add(new AssertionRequirement(handler));return this;}public AuthorizationPolicyBuilder RequireAssertion(Func<AuthorizationHandlerContext, Task<bool>> handler){if (handler == null){throw new ArgumentNullException(nameof(handler));}Requirements.Add(new AssertionRequirement(handler));return this;}public AuthorizationPolicy Build(){return new AuthorizationPolicy(Requirements, AuthenticationSchemes.Distinct());}
}

由上面多出出现的IAuthorizationRequirement对象可以发现,授权要求Requirement属性是策略的核心方案,每一种Requirement都代表一种授权方式。同时IAuthorizationPolicyBuilder为这些预定义的方案创建了它们对应的使用方式并将其添加到Requirements集合中。

2.5 授权要求IAuthorizationRequirement

    public interface IAuthorizationRequirement{}

接口并没有任何实现成员,因为授权要求是具有不同的表现形式的,所有才没有具体的实现成员。授权要求目的在于检验某个当前用户是否具有相应的要求,  所以大部分IAuthorizationRequirement接口的实现类都继承了IAuthorizationHandler 接口来提供HandleAsync方法来实现对应的授权检验。

下面介绍asp.net core框架里面默认实现的几种IAuthorizationRequirement实现类型。

2.5.1 DenyAnonymousAuthorizationRequirement

阻止匿名用户操作,言外之意就是拒绝未被验证的匿名用户访问资源。

源码如下:

public class DenyAnonymousAuthorizationRequirement : AuthorizationHandler<DenyAnonymousAuthorizationRequirement>, IAuthorizationRequirement
{protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, DenyAnonymousAuthorizationRequirement requirement){var user = context.User;var userIsAnonymous =user?.Identity == null ||!user.Identities.Any(i => i.IsAuthenticated);if (!userIsAnonymous){context.Succeed(requirement);}return Task.CompletedTask;}
}

通过用户的CliamPrincipal对象身份是否为空或是否是一个经过认证的用户身份,以此来确定当前请求的用户是否来源于匿名用户。

2.5.2 NameAuthorizationRequirement

指定用户名的授权方式,判断当前用户与某个指定的用户是否匹配以此来授权访问资源。

源码如下:

public class NameAuthorizationRequirement : AuthorizationHandler<NameAuthorizationRequirement>, IAuthorizationRequirement
{public NameAuthorizationRequirement(string requiredName){if (requiredName == null){throw new ArgumentNullException(nameof(requiredName));}RequiredName = requiredName;}public string RequiredName { get; }protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NameAuthorizationRequirement requirement){if (context.User != null){if (context.User.Identities.Any(i => string.Equals(i.Name, requirement.RequiredName))){context.Succeed(requirement);}}return Task.CompletedTask;}
}

其中RequiredName属性为授权用户,通过HandleRequirementAsync方法进行校验当前用户的ClaimPrincipal对象的身份与RequiredName是否具有匹配。

这里的判断用的是 string.Equals() 说明这里比较的用户名是区别大小写的。

2.5.3 ClaimsAuthorizationRequirement

基于指定声明类型的授权策略,检验当前用户是否声明类型和候选值。

源码如下:

public class ClaimsAuthorizationRequirement : AuthorizationHandler<ClaimsAuthorizationRequirement>, IAuthorizationRequirement{public ClaimsAuthorizationRequirement(string claimType, IEnumerable<string> allowedValues){if (claimType == null){throw new ArgumentNullException(nameof(claimType));}ClaimType = claimType;AllowedValues = allowedValues;}public string ClaimType { get; }public IEnumerable<string> AllowedValues { get; }protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ClaimsAuthorizationRequirement requirement){if (context.User != null){var found = false;if (requirement.AllowedValues == null || !requirement.AllowedValues.Any()){found = context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase));}else{found = context.User.Claims.Any(c => string.Equals(c.Type, requirement.ClaimType, StringComparison.OrdinalIgnoreCase)&& requirement.AllowedValues.Contains(c.Value, StringComparer.Ordinal));}if (found){context.Succeed(requirement);}}return Task.CompletedTask;}}

由上我们可以看的出,ClaimTypeAllowedValues这两个属性在构造函数中被初始化,分别用来表示当前声明的声明类型和默认允许值。通过HandleRequirementAsync来授权检验是否完成通过。

2.5.4  RolesAuthorizationRequirement

基于角色的授权策略,检验当前用户是否拥有约定匹配的角色,如果拥有,则可以访问对应的资源。

源码如下:

public class RolesAuthorizationRequirement : AuthorizationHandler<RolesAuthorizationRequirement>, IAuthorizationRequirement
{public RolesAuthorizationRequirement(IEnumerable<string> allowedRoles){if (allowedRoles == null){throw new ArgumentNullException(nameof(allowedRoles));}if (allowedRoles.Count() == 0){throw new InvalidOperationException(Resources.Exception_RoleRequirementEmpty);}AllowedRoles = allowedRoles;}public IEnumerable<string> AllowedRoles { get; }protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, RolesAuthorizationRequirement requirement){if (context.User != null){bool found = false;if (requirement.AllowedRoles == null || !requirement.AllowedRoles.Any()){// Review: What do we want to do here?  No roles requested is auto success?}else{found = requirement.AllowedRoles.Any(r => context.User.IsInRole(r));}if (found){context.Succeed(requirement);}}return Task.CompletedTask;}
}

其中AllowedRoles表示目标角色列表的集合。通过HandleRequirementAsync实现授权检验,调用IsInRole方法来判断当前用户的ClaimsPrincipal对象是否有指定的角色。

2.5.5  AssertionRequirement

基于AuthorizationHandlerContext上下文断言的形式来声明授权。

源码如下:


public class AssertionRequirement : IAuthorizationHandler, IAuthorizationRequirement
{public Func<AuthorizationHandlerContext, Task<bool>> Handler { get; }public AssertionRequirement(Func<AuthorizationHandlerContext, bool> handler){if (handler == null){throw new ArgumentNullException(nameof(handler));}Handler = context => Task.FromResult(handler(context));}public AssertionRequirement(Func<AuthorizationHandlerContext, Task<bool>> handler){if (handler == null){throw new ArgumentNullException(nameof(handler));}Handler = handler;}public async Task HandleAsync(AuthorizationHandlerContext context){if (await Handler(context)){context.Succeed(this);}}
}

通过类型为Func<AuthorizationHandlerContext, Task<bool>>的委托来表示该断言,利用它来授权验证。在HandleAsync检验方法中,直接调用这个委托对象来完成判断。

2.5.6 OperationAuthorizationRequirement

基于预定义操作的授权策略。

源码如下:

public class OperationAuthorizationRequirement : IAuthorizationRequirement
{public string Name { get; set; }
}

由上可知,只是包含一个操作名字的Name属性,目的在于将授权的目标对象映射到一个预定义的操作上。

三、用例

出现的IAuthorizationRequirement对象可以发现,授权要求Requirement属性是策略的核心方案,每一中Requirement都代表一种授权方式。

在上文我们通过构建策略AuthorizationPolicyBuilder对象的源码可以发现,为我们提供了多个方法由预定义的IAuthorizationRequirement类型来创建并将其添加到Requirements集合中。

3.1 应用

实例应用如下:在ConfigureServices中配置服务中

        public void ConfigureServices(IServiceCollection services){services.AddControllers();var combindPolicy = new AuthorizationPolicyBuilder().RequireClaim("role").Build();services.AddAuthorization(options =>{//DenyAnonymousAuthorizationRequirementoptions.AddPolicy("DenyAnonyUser", policy => policy.RequireAuthenticatedUser());//NameAuthorizationRequirementoptions.AddPolicy("NameAuth", policy => policy.RequireUserName("艾三元"));//ClaimsAuthorizationRequirementoptions.AddPolicy("ClaimsAuth", policy => policy.RequireClaim("role","admin"));//RolesAuthorizationRequirementoptions.AddPolicy("RolesAuth", policy => policy.RequireRole("admin","user"));//AssertionRequirementoptions.AddPolicy("AssertAuth", policy => policy.RequireAssertion(c=>c.User.HasClaim(o=>o.Type=="role")));//同样可可用直接调用Combind方法,策略AuthorizationPolicyoptions.AddPolicy("CombindAuth", policy => policy.Combine(combindPolicy));});
}

以上,分别实现了框架中默认实现的几种IAuthorizationRequirement实现类型在实际中的应用,通过不同授权要求实现的策略方式,同时也可以将上面多种方式合并成一个对象,进行调用使用。

3.2 拓展

当然了,除了自带了这几种默认实现方式之外,我们也可以通过自定义Requirement来满足我们的需求。

这个在上一节初识授权的时候,已经提到了自定义授权这一块,所以在这里再看一次。

定义一个权限策略PermissionRequirement,这个策略并包含一些属性。

public class PermissionRequirement: IAuthorizationRequirement
{public string _permissionName { get; }public PermissionRequirement(string PermissionName){_permissionName = PermissionName;}
}

再定义一个策略处理类

public class PermissionRequirementHandler : AuthorizationHandler<PermissionRequirement>
{protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement){var role = context.User.FindFirst(c => c.Type == ClaimTypes.Role);if (role != null){var roleValue = role.Value;if (roleValue==requirement._permissionName){context.Succeed(requirement);}}return Task.CompletedTask;

配置使用

    public void ConfigureServices(IServiceCollection services){services.AddControllers();//基于自定义策略授权services.AddAuthorization(options =>{options.AddPolicy("customizePermisson",policy => policy.Requirements.Add(new PermissionRequirement("admin")));});//此外,还需要在 IAuthorizationHandler 类型的范围内向 DI 系统注册新的处理程序:services.AddScoped<IAuthorizationHandler, PermissionRequirementHandler>();// 如前所述,要求可包含多个处理程序。如果为授权层的同一要求向 DI 系统注册多个处理程序,有一个成功就足够了。}

特别说明

上述使用的处理程序是一对一的关系,当声明要求满足条件的时候,则任务授权成功, 授权成功后, context.Succeed 将通过满足要求作为其唯一参数调用。

但是授权策略中也包含一对多的要求关系,它们属于 & 的关系,只用全部验证通过,才能最终授权成功。但是在有些场景下,我们可能希望一个授权策略可以适用多种情况,比如,我们进入公司时需要出示员工卡才可以被授权进入,但是如果我们忘了带员工卡,可以去申请一个临时卡,同样可以授权成功。

这里贴一个官方文档的写法:public class BuildingEntryRequirement : IAuthorizationRequirement
{
}
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,BuildingEntryRequirement requirement){if (context.User.HasClaim(c => c.Type == "BadgeId" &&c.Issuer == "http://microsoftsecurity")){context.Succeed(requirement);}//TODO: Use the following if targeting a version of//.NET Framework older than 4.6://      return Task.FromResult(0);return Task.CompletedTask;}
}
public class TemporaryStickerHandler : AuthorizationHandler<BuildingEntryRequirement>
{protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,BuildingEntryRequirement requirement){if (context.User.HasClaim(c => c.Type == "TemporaryBadgeId" &&c.Issuer == "https://microsoftsecurity")){// We'd also check the expiration date on the sticker.context.Succeed(requirement);}//TODO: Use the following if targeting a version of//.NET Framework older than 4.6://      return Task.FromResult(0);return Task.CompletedTask;}
}

我们定义了两个Handler,但是想让它们得到执行,还需要将其注册到DI系统中:

services.AddSingleton<IAuthorizationHandler, BadgeEntryHandler>();
services.AddSingleton<IAuthorizationHandler, TemporaryStickerHandler>();

确保两个处理程序都已注册。如果某个处理程序在某一策略评估后使用context.succeed()来成功 BuildingEntryRequirement ,则策略评估将成功。但是当我们调用context.Fail()方法后会将授权结构设置失败,那样的话,最后的结果都是会授权失败的。所以正常情况下。我们都是只设置标记context.succeed()

四、说明

这里对上文源码中出现的一些声明方法进行说明。

4.1 IAuthorizeData

使用 IAuthorizeDate 接口方法。定义授权规则应用于资源所需的数据集。

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

Policy:获取或设置确定对资源的访问的策略名称。

Roles:      获取或设置以逗号分隔的允许访问资源的角色列表。

AuthenticationSchemes:   获取或以设置以逗号分隔的方案列表,从中可以构造用户信息。

所以IAuthorizeData中定义的policyrolesAuthenticationSchemes三个分别代表着授权系统中的三种授权方式。

具体的使用在后续讲解授权的执行流程中会进行详细介绍。

五、后续

上面主要讲解了授权在配置方面的源码,本来打算继续接着往下写的,但是考虑到整体篇幅可能会太长了,不便于阅读。

所以授权揭秘的上篇内容就说到这里了,在后续的文章中,会继续深入了解授权内部机制的奥秘以及是如何实现执行授权流程的。

六、总结

  1. 从添加授权配置开始,我们引入了需要的授权配置选项,而不同的授权要求构建不同的策略方式,从而实现一种自己满意的授权需求配置要求。

  2. 如果有不对的或不理解的地方,希望大家可以多多指正,提出问题,一起讨论,不断学习,共同进步。

  3. 参考的文档 和官方源码

往期精彩回顾

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308887.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Singleton(单件)--对象创建模式

Singleton&#xff08;单件&#xff09;–对象创建模式 一、意图 保证一个类仅有一个实例&#xff0c;并提供一个访问它的全局访问点。 二、动机 1.在软件系统中&#xff0c;经常有这样一些特殊的类&#xff0c;必须保证它们在系统中只存在一个实例&#xff0c;才能确保它们的…

龙芯团队 在移值 MIPS64 下的.NET Core 进度速报

写在开始前我们的主要业务基于 dotnet core 2.x 与 3.1 完成&#xff0c;目前 dotnet core 3.1 支持的 CPU 架构列表中还不包含龙芯&#xff0c;且在 gitlab issue 中表示官方当前没有对 MIPS 的支持计划。更具体操作系统与 CPU 架构列表见 [Download .NET Core 3.1](https://d…

Adapter(适配器)--类对象结构型模式

Adapter&#xff08;适配器&#xff09;–类对象结构型模式 一、意图 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本接口不兼容而不能一起工作的那些类可以一起工作。 二、动机 1.在软件系统中&#xff0c;由于应用环境的变化&#xff0c;常常需要将“一…

如何使用ABP框架(2)三层架构与领域驱动设计的对比

本文来自长沙.NET技术社区&#xff0c;原创&#xff1a;邹溪源。全文共有8500字&#xff0c;读完需耗时10分钟。题图来自pixabay简述上一篇简述了ABP框架中的一些基础理论&#xff0c;包括ABP前后端项目的分层结构&#xff0c;以及后端项目中涉及到的知识点&#xff0c;例如DTO…

Bridge(桥接)--对象结构模式

Bridge&#xff08;桥接&#xff09;–对象结构模式 一、意图 将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立的变化。 二、动机 1.由于某些类型的固有的实现逻辑&#xff0c;使得它们具有两个变化的维度&#xff0c;乃至多个纬度的变化。 2.如何应对这种“多维度…

Composite(组合)--对象结构型模式

Composite&#xff08;组合&#xff09;–对象结构型模式 一、意图 将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。 二、动机 1.软件在某些情况下&#xff0c;客户代码过多的依赖于对象容器复杂的内部实现结构…

[SpringBoot2]ajax函数中data参数的数据设置方式

ajax函数中data参数的数据设置方式&#xff1a;

Blazor带我重玩前端(二)

概览Blazor目前有两种托管模式&#xff0c;一种是Server-Side模式&#xff0c;一种是WebAssembly模式。官方首先支持的是Service-Side模式&#xff0c;使用WebAssembly模式&#xff0c;需要更新到最新版VS2019。小编目前的精力是更多的专注于Blazor-WebAssembly模式的研究&…

Decorator(装饰)--对象结构型模式

Decorator&#xff08;装饰&#xff09;–对象结构型模式 一、意图 1.动态地给一个对象添加一些额外的职责。就增加功能来说&#xff0c;Decorator模式相比生成子类更为灵活。 二、动机 1.在某些情况下我们可能会“过度地使用继承来扩展对象的功能”&#xff0c; 由于继承为类…

Facade(外观)--对象结构型模式

Facade&#xff08;外观&#xff09;–对象结构型模式 一、意图 为子系统中的一组接口提供一个一致的界面&#xff0c;Facade模式定义了一个高层接口&#xff0c;这个接口使得这一子系统更加容易使用。 二、动机 1.上述左边方案的问题在于组件的客户和组件中各种复杂的子系…

.NET Core微服务开发网篇-ocelot

通过上篇我们知道&#xff0c;网关是外部访问的统一入口&#xff0c;本文采用Ocelot作为Api网关。环境要求&#xff1a;vs2019.NetCore3.1Ocelot16.0.1创建一个产品服务Api站点&#xff08;AAStore.ProductCatalog.Api&#xff09;添加一个ProductController[Route("api/[…

Flyweight(享元)--对象结构型模式

Flyweight&#xff08;享元&#xff09;–对象结构型模式 一、意图 运行共享技术有效地支持大量细粒度的对象。 二、动机 1.在软件系统采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中&#xff0c;从而带来很高的运行时代价——主要指内存需求方面的代价。 2.…

IBM 声明对 Google 违背承诺未将 Istio 贡献给 CNCF 表示失望

Jason R McGee&#xff0c;IBM 院士&#xff0c;IBM 云平台副总裁兼 CTO。昨天晚上Google 宣布将 Istio 商标转让给 Open Usage Commons 组织&#xff0c;IBM 当即在 IBM Developer 网站上发表声明对 Google 的做法表示失望。以下为 IBM 云平台副总裁兼 CTO Jason R McGee 的声…

[mybatis]Configuration XML_properties

properties mybatis可以使用properties来引入外部properties配置文件的内容 resource:引入类路径下的资源 url:引入网络路径或者磁盘路径下的资源 process 项目结构: mybatis-config.xml: <?xml version"1.0" encoding"UTF-8" ?> <!DOCTY…

Proxy(代理)--对象结构型模式

Proxy&#xff08;代理&#xff09;–对象结构型模式 一、意图 为其他对象提供一种代理以控制对这个对象的访问。 二、动机 1.在面向对象系统中&#xff0c;有些对象由于某种原因&#xff08;比如对象创建的开销很大&#xff0c;或者某些操作需要安全控制&#xff0c;或者需要…

浅谈.Net Core DependencyInjection源码探究

前言对于IOC和DI&#xff0c;可能每个人都能说出自己的理解。IOC全称是Inversion of Control翻译成中文叫控制反转&#xff0c;简单的说就是把对象的控制权反转到IOC容器中&#xff0c;由IOC管理其生命周期。DI全称是DependencyInjection翻译成中文叫依赖注入&#xff0c;就是I…

[mybatis]Configuration XML_settings

settings settings包含很多重要的设置项 setting:用来设置每一个设置项name:设置项名value:设置项取值 mapUnderscoreToCamelCase 开启驼峰命名法 <settings><setting name"mapUnderscoreToCamelCase" value"true"/></settings>Emplo…

Chain of responsibility(职责链)--对象行为型模式

Chain of responsibility&#xff08;职责链&#xff09;–对象行为型模式 一、意图 使多个对象有机会处理请求&#xff0c;从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链&#xff0c;并沿着这条链传递该请求&#xff0c;直到有一个对象处理它为止。 二…

[mybatis]Configuration XML_typeAliases and Alias

There are many built-in type aliases for common Java types. They are all case insensitive, note the special handling of primitives due to the overloaded names. typeAliases typeAlias:为某个java类型起别名 type:指定要起别名的类型全类名;默认别名就是类名小写;em…

Command(命令)--对象行为型模式

Command&#xff08;命令&#xff09;–对象行为型模式 一、意图 将一个请求封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化&#xff1b;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 二、动机 1.在软件构建过程中&#xff0c;“行为请求…