基于.NetCore3.1系列 —— 认证授权方案之授权揭秘 (下篇)

一、前言

回顾:基于.NetCore3.1系列 —— 认证授权方案之授权揭秘 (上篇)

在上一篇中,主要讲解了授权在配置方面的源码,从添加授权配置开始,我们引入了需要的授权配置选项,而不同的授权要求构建不同的策略方式,从而实现一种自己满意的授权需求配置要求。

在这一节中,继续上一篇的内容往下深入了解授权内部机制的奥秘以及是如何实现执行授权流程的。

二、说明

在上一篇中,我们通过定义授权策略,查看源码发现,在对授权配置AuthorizationOptions之后,授权系统通过DI的方式注册了几个核心的默认实现。

之前我们进行对步骤一的授权有了大概了解,所以下面我们将对步骤二进行的注册对象进行说明。

三、开始

3.1 IAuthorizationService

授权服务接口,用来确定授权是否成功的主要服务,接口的定义为

    public interface IAuthorizationService{Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements);Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName);}

两个接口的参数不同之处在于IAuthorizationRequirementpolicyName,分别是指定资源的一组特定要求和指定的授权名称。

同时asp.net core还为IAuthorizationService接口拓展了几个方法:

    public static class AuthorizationServiceExtensions{public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, IAuthorizationRequirement requirement){if (service == null){throw new ArgumentNullException(nameof(service));}if (requirement == null){throw new ArgumentNullException(nameof(requirement));}return service.AuthorizeAsync(user, resource, new IAuthorizationRequirement[] { requirement });}public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, object resource, AuthorizationPolicy policy){if (service == null){throw new ArgumentNullException(nameof(service));}if (policy == null){throw new ArgumentNullException(nameof(policy));}return service.AuthorizeAsync(user, resource, policy.Requirements);}public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, AuthorizationPolicy policy){if (service == null){throw new ArgumentNullException(nameof(service));}if (policy == null){throw new ArgumentNullException(nameof(policy));}return service.AuthorizeAsync(user, resource: null, policy: policy);}public static Task<AuthorizationResult> AuthorizeAsync(this IAuthorizationService service, ClaimsPrincipal user, string policyName){if (service == null){throw new ArgumentNullException(nameof(service));}if (policyName == null){throw new ArgumentNullException(nameof(policyName));}return service.AuthorizeAsync(user, resource: null, policyName: policyName);}}

接口的默认实现为DefaultAuthorizationService

DefaultAuthorizationService的实现主要是用来对 IAuthorizationRequirement对象的授权检验。

public class DefaultAuthorizationService : IAuthorizationService
{private readonly AuthorizationOptions _options;private readonly IAuthorizationHandlerContextFactory _contextFactory;private readonly IAuthorizationHandlerProvider _handlers;private readonly IAuthorizationEvaluator _evaluator;private readonly IAuthorizationPolicyProvider _policyProvider;private readonly ILogger _logger;public DefaultAuthorizationService(IAuthorizationPolicyProvider policyProvider, IAuthorizationHandlerProvider handlers, ILogger<DefaultAuthorizationService> logger, IAuthorizationHandlerContextFactory contextFactory, IAuthorizationEvaluator evaluator, IOptions<AuthorizationOptions> options){if (options == null){throw new ArgumentNullException(nameof(options));}if (policyProvider == null){throw new ArgumentNullException(nameof(policyProvider));}if (handlers == null){throw new ArgumentNullException(nameof(handlers));}if (logger == null){throw new ArgumentNullException(nameof(logger));}if (contextFactory == null){throw new ArgumentNullException(nameof(contextFactory));}if (evaluator == null){throw new ArgumentNullException(nameof(evaluator));}_options = options.Value;_handlers = handlers;_policyProvider = policyProvider;_logger = logger;_evaluator = evaluator;_contextFactory = contextFactory;}public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements){if (requirements == null){throw new ArgumentNullException(nameof(requirements));}var authContext = _contextFactory.CreateContext(requirements, user, resource);var handlers = await _handlers.GetHandlersAsync(authContext);foreach (var handler in handlers){await handler.HandleAsync(authContext);if (!_options.InvokeHandlersAfterFailure && authContext.HasFailed){break;}}var result = _evaluator.Evaluate(authContext);if (result.Succeeded){_logger.UserAuthorizationSucceeded();}else{_logger.UserAuthorizationFailed();}return result;}public async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName){if (policyName == null){throw new ArgumentNullException(nameof(policyName));}var policy = await _policyProvider.GetPolicyAsync(policyName);if (policy == null){throw new InvalidOperationException($"No policy found: {policyName}.");}return await this.AuthorizeAsync(user, resource, policy);}
}

通过上面的代码可以发现,在对象实例中,通过构造函数的方式分别注入了IAuthorizationPolicyProviderIAuthorizationHandlerProviderIAuthorizationEvaluatorIAuthorizationHandlerContextFactory这几个核心服务,以及配置选项的AuthorizationOptions对象,再通过实现的方法AuthorizeAsync可以看出,在方法中调用GetPolicyAsync来获取Requirements,具体的可以看一下上一节的AuthorizationPolicy,而后在根据授权上下文来判断。

这里就用到了注入的几个核心对象来实现完成授权的。下面会分别介绍到的。

3.2 IAuthorizationPolicyProvider

由上面的IAuthorizationServer接口的默认实现可以发现,在进行授权检验的时候,DefaultAuthorizationService会利用注入的IAuthorizationPolicyProvider服务来提供注册的授权策略,所以我们查看源码发现,接口提供 了默认的授权策略GetDefaultPolicyAsync和指定名称的授权策略·GetPolicyAsync(string policyName)的方法。

public interface IAuthorizationPolicyProvider
{Task<AuthorizationPolicy> GetPolicyAsync(string policyName);Task<AuthorizationPolicy> GetDefaultPolicyAsync();Task<AuthorizationPolicy> GetFallbackPolicyAsync();
}

再加上在使用[Authorize]进行策略授权的时候,会根据提供的接口方法来获取指定的授权策略。

IAuthorizationPolicyProvider来根据名称获取到策略对象,默认实现为DefaultAuthorizationPolicyProvider

DefaultAuthorizationPolicyProvider

    public class DefaultAuthorizationPolicyProvider : IAuthorizationPolicyProvider{private readonly AuthorizationOptions _options;private Task<AuthorizationPolicy> _cachedDefaultPolicy;private Task<AuthorizationPolicy> _cachedFallbackPolicy;public DefaultAuthorizationPolicyProvider(IOptions<AuthorizationOptions> options){if (options == null){throw new ArgumentNullException(nameof(options));}_options = options.Value;}public Task<AuthorizationPolicy> GetDefaultPolicyAsync(){return GetCachedPolicy(ref _cachedDefaultPolicy, _options.DefaultPolicy);}public Task<AuthorizationPolicy> GetFallbackPolicyAsync(){return GetCachedPolicy(ref _cachedFallbackPolicy, _options.FallbackPolicy);}private Task<AuthorizationPolicy> GetCachedPolicy(ref Task<AuthorizationPolicy> cachedPolicy, AuthorizationPolicy currentPolicy){var local = cachedPolicy;if (local == null || local.Result != currentPolicy){cachedPolicy = local = Task.FromResult(currentPolicy);}return local;}public virtual Task<AuthorizationPolicy> GetPolicyAsync(string policyName){return Task.FromResult(_options.GetPolicy(policyName));}}

由上面的代码可以看出,在实现DefaultAuthorizationPolicyProvider对象进行构造函数的方式注入了IOptions<AuthorizationOptions> options服务来提供配置选项AuthorizationOptions(不懂的可以查看上一篇的AuthorizationOptions),再通过实现的方法可以看出是如何获取到注册的授权策略的了。附加一个图片

在上一章中介绍过,我们定义的策略都保存在AuthorizationOptions的中PolicyMap字典中,由上代码可以发现这字典的用处。

3.3 IAuthorizationHandlerContextFactory

先看看这个接口的源代码

public interface IAuthorizationHandlerContextFactory
{AuthorizationHandlerContext CreateContext(IEnumerable<IAuthorizationRequirement> requirements, ClaimsPrincipal user, object resource);
}

接口定义了一个唯一的方法CreateContext,作用在于创建授权上下文AuthorizationHandlerContext对象。接口默认实现方式

    public class DefaultAuthorizationHandlerContextFactory : IAuthorizationHandlerContextFactory{public virtual AuthorizationHandlerContext CreateContext(IEnumerable<IAuthorizationRequirement> requirements, ClaimsPrincipal user, object resource){return new AuthorizationHandlerContext(requirements, user, resource);}}

再来看看AuthorizationHandlerContext授权上下文对象,可以看出,上下文中主要包括用户的Claims和授权策略的要求Requirements

public class AuthorizationHandlerContext
{private HashSet<IAuthorizationRequirement> _pendingRequirements;private bool _failCalled;private bool _succeedCalled;public AuthorizationHandlerContext(IEnumerable<IAuthorizationRequirement> requirements,ClaimsPrincipal user,object resource){if (requirements == null){throw new ArgumentNullException(nameof(requirements));}Requirements = requirements;User = user;Resource = resource;_pendingRequirements = new HashSet<IAuthorizationRequirement>(requirements);}public virtual IEnumerable<IAuthorizationRequirement> Requirements { get; }public virtual ClaimsPrincipal User { get; }public virtual object Resource { get; }public virtual IEnumerable<IAuthorizationRequirement> PendingRequirements { get { return _pendingRequirements; } }public virtual bool HasFailed { get { return _failCalled; } }public virtual bool HasSucceeded{get{return !_failCalled && _succeedCalled && !PendingRequirements.Any();}}public virtual void Fail(){_failCalled = true;}public virtual void Succeed(IAuthorizationRequirement requirement){_succeedCalled = true;_pendingRequirements.Remove(requirement);}
}

因此,在下面我们刚好会提到了IAuthorizationHandlerProvider中的方法,可以根据授权上下文获取到请求调用的处理程序。

3.4 IAuthorizationHandlerProvider  

这个是接口的方法,作用是获取所有的授权Handler

public interface IAuthorizationHandlerProvider
{Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync(AuthorizationHandlerContext context);
}

根据之前提到的授权上下文作为GetHandlersAsync方法参数对象来提取IAuthorizationHandler对象。

默认接口的实现为DefaultAuthorizationHandlerProvider, 处理程序的默认实现,为授权请求提供IAuthorizationHandler

    public class DefaultAuthorizationHandlerProvider : IAuthorizationHandlerProvider{private readonly IEnumerable<IAuthorizationHandler> _handlers;public DefaultAuthorizationHandlerProvider(IEnumerable<IAuthorizationHandler> handlers){if (handlers == null){throw new ArgumentNullException(nameof(handlers));}_handlers = handlers;}public Task<IEnumerable<IAuthorizationHandler>> GetHandlersAsync(AuthorizationHandlerContext context)=> Task.FromResult(_handlers);}

从默认实现的方式可以看出,利用构造函数的方式注入默认的IAuthorizationHandler的对象,但是我们再看看接口的实现方法可以发现,GetHandlersAsync返回的IAuthorizationHandler对象并不是从给定的AuthorizationHandlerContext上下文中获取的,而是直接通过构造函数的方式注入得到的。

这个时候,你可能会问,那么IAuthorizationHandler是在哪里注入的呢?

对应下面的 IAuthorizationHandler

3.5 IAuthorizationEvaluator  

DefaultAuthorizationService中的授权方法过程调用了

   var result = _evaluator.Evaluate(authContext);

IAuthorizationEvaluator接口,来确定授权结果是否成功。

    public interface IAuthorizationEvaluator{AuthorizationResult Evaluate(AuthorizationHandlerContext context);}

IAuthorizationEvaluator的唯一方法Evaluate,该方法会根据之前提供的授权上下文返回一个表示授权成功的AuthorizationResult对象。默认实现为DefaultAuthorizationEvaluator

public class DefaultAuthorizationEvaluator : IAuthorizationEvaluator
{public AuthorizationResult Evaluate(AuthorizationHandlerContext context)=> context.HasSucceeded? AuthorizationResult.Success(): AuthorizationResult.Failed(context.HasFailed? AuthorizationFailure.ExplicitFail(): AuthorizationFailure.Failed(context.PendingRequirements));
}

由默认实现可以看出,AuthorizationHandlerContext对象的HasSucceeded属性决定了授权是否成功。当验证通过时,授权上下文中的HasSucceeded才会为True。

其中的AuthorizationResultAuthorizationFailure分别为

public class AuthorizationResult
{private AuthorizationResult() { }public bool Succeeded { get; private set; }public AuthorizationFailure Failure { get; private set; }public static AuthorizationResult Success() => new AuthorizationResult { Succeeded = true };public static AuthorizationResult Failed(AuthorizationFailure failure) => new AuthorizationResult { Failure = failure };public static AuthorizationResult Failed() => new AuthorizationResult { Failure = AuthorizationFailure.ExplicitFail() };}
public class AuthorizationFailure
{private AuthorizationFailure() { }public bool FailCalled { get; private set; }public IEnumerable<IAuthorizationRequirement> FailedRequirements { get;private set; }public static AuthorizationFailure ExplicitFail()=> new AuthorizationFailure{FailCalled = true,FailedRequirements = new IAuthorizationRequirement[0]};public static AuthorizationFailure Failed(IEnumerable<IAuthorizationRequirement> failed)=> new AuthorizationFailure { FailedRequirements = failed };
}

这里的两个授权结果 正是IAuthorizationService 进行实现授权AuthorizeAsync来完成校验返回的结果。

3.6 IAuthorizationHandler

接口方式实现,判断是否授权,实现此接口的类

public interface IAuthorizationHandler
{Task HandleAsync(AuthorizationHandlerContext context);
}

如果允许授权,可通过此接口的方法来决定是否允许授权。

之前我们还介绍到,我们定义的Requirement,可以直接实现IAuthorizationHandler接口,也可以单独定义Handler,但是需要注册到DI系统中去。

在默认的AuthorizationHandlerProvider中,会从DI系统中获取到我们注册的所有Handler,最终调用其HandleAsync方法。

我们在实现IAuthorizationHandler接口时,通常是继承自AuthorizationHandler来实现,它有如下定义:

public abstract class AuthorizationHandler<TRequirement> : IAuthorizationHandler where TRequirement : IAuthorizationRequirement
{
public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
foreach (var req in context.Requirements.OfType<TRequirement>())
{await HandleRequirementAsync(context, req);
}
}protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement);
}

如上,首先会在HandleAsync过滤出与Requirement对匹配的Handler,然后再调用其HandleRequirementAsync方法。

那我们定义的直接实现IAuthorizationHandler了接口的Requirement又是如何执行的呢?

我们可以发现,IAuthorizationHandlerAddAuthorization拓展方法中可以看到默认注册了一个PassThroughAuthorizationHandler默认实现为:

public class PassThroughAuthorizationHandler : IAuthorizationHandler
{public async Task HandleAsync(AuthorizationHandlerContext context){foreach (var handler in context.Requirements.OfType<IAuthorizationHandler>()){await handler.HandleAsync(context);}}
}

它负责调用该策略中所有实现了IAuthorizationHandler接口的Requirement。通过接口实现的方法可以看出,当PassThroughAuthorizationHandler对象的HandleAsync方法被执行的时候,它会从AuthroizationHanderContextRequirements属性中提取所有的IAuthoizationHandler对象,并逐个调用它们的HandleAsync方法来实施授权检验。

所以可以看到的出,PassThroughAuthorizationHandler是一个特殊并且重要的授权处理器类型,其特殊之处在于它并没有实现针对某个具体规则的授权检验,但是AuthorizationHandlerContext上下文所有的IAuthorizationHandler都是通过该对象驱动执行的。

3.7 IPolicyEvaluator  

接口的方式实现,为特定需求类型调用的授权处理程序的基类

    public interface IPolicyEvaluator{Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context);Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource);}

定义了两个方法AuthenticateAsyncAuthorizeAsync方法

IPolicyEvaluator的默认实现为PolicyEvaluator

    public class PolicyEvaluator : IPolicyEvaluator{private readonly IAuthorizationService _authorization;public PolicyEvaluator(IAuthorizationService authorization){_authorization = authorization;}public virtual async Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context){if (policy.AuthenticationSchemes != null && policy.AuthenticationSchemes.Count > 0){ClaimsPrincipal newPrincipal = null;foreach (var scheme in policy.AuthenticationSchemes){var result = await context.AuthenticateAsync(scheme);if (result != null && result.Succeeded){newPrincipal = SecurityHelper.MergeUserPrincipal(newPrincipal, result.Principal);}}if (newPrincipal != null){context.User = newPrincipal;return AuthenticateResult.Success(new AuthenticationTicket(newPrincipal, string.Join(";", policy.AuthenticationSchemes)));}else{context.User = new ClaimsPrincipal(new ClaimsIdentity());return AuthenticateResult.NoResult();}}return (context.User?.Identity?.IsAuthenticated ?? false)? AuthenticateResult.Success(new AuthenticationTicket(context.User, "context.User")): AuthenticateResult.NoResult();}public virtual async Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource){if (policy == null){throw new ArgumentNullException(nameof(policy));}var result = await _authorization.AuthorizeAsync(context.User, resource, policy);if (result.Succeeded){return PolicyAuthorizationResult.Success();}// If authentication was successful, return forbidden, otherwise challengereturn (authenticationResult.Succeeded)? PolicyAuthorizationResult.Forbid(): PolicyAuthorizationResult.Challenge();}}

授权中间件委托它来实现身份验证和授权处理,它内部会调用AuthorizationService,进而执行所有授权处理器AuthorizationHandler, (在后面会提到授权中间件用到这两个方法)

3.7.1、AuthenticateAsync

当授权策略没有设置AuthenticationSchemes,则只判断下当前请求是否已做身份验证,若做了就返回成功当授权策略设置了AuthenticationSchemes,则遍历身份验证方案逐个进行身份验证处理 。

其中context.User就是使用context.AuthenticateAsync(DefaultAuthenticateScheme)来赋值的,将所有得到的用户标识重组成一个复合的用户标识。

当我们希望使用非默认的Scheme,或者是想合并多个认证Scheme的Claims时,就需要使用基于Scheme的授权来重置Claims了。

它的实现也很简单,直接使用我们在授权策略中指定的Schemes来依次调用认证服务的AuthenticateAsync方法,并将生成的Claims合并,最后返回我们熟悉的AuthenticateResult认证结果。

3.7.2、AuthorizeAsync

该方法会根据Requirements来完成授权,具体的实现是通过调用IAuthorizationService调用AuthorizeAsync来实现的。

最终返回的是一个PolicyAuthorizationResult对象,并在授权失败时,根据认证结果来返回Forbid(未授权)Challenge(未登录)


以上汇总

  1. 授权服务IAuthorizationService,接口的默认实现为DefaultAuthorizationService,进行授权验证。

  2. 在会根据授权策略提供器IAuthorizationPolicyProvider来获取指定名称的授权。

  3. 通过授权处理器上下文对象工厂IAuthorizationHandlerContextFactory授权处理器AuthorizationHandler在授权时需要传入AuthorizationHandlerContext(上面说了授权完成后的结果也存储在里面)。所以在执行授权处理器之前需要构建这个上下文对象,就是通过这个工厂构建的,主要的数据来源就是 当前 或者 指定的 授权策略AuthorizationPolicy。

  4. 所以这个时候会授权处理提供其 IAuthorizationHandlerProvider,来获取系统中所有授权处理器。

  5. 授权评估器IAuthorizationEvaluator来确定授权结果是否成功,在授权处理器AuthorizationHandler在执行完授权后,结果是存储在AuthorizationHandlerContext中的,这里的评估器只是根据AuthorizationHandlerContext创建一个授权结果AuthorizationResult。

  6. 上面所说的授权处理器就是IAuthorizationHandler,处理器中包含主要的授权逻辑,在处理的过程中会将所有的授权处理器一一验证。

  7. 所以在授权中间件中会利用IPolicyEvaluator中实现的身份认证和授权处理方法来调用AuthorizationService来执行所有的处理器。

四、中间件

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

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

在这里使用了授权中间件来检查授权,来看看中间件的源码AuthorizationMiddleware

public class AuthorizationMiddleware
{// Property key is used by Endpoint routing to determine if Authorization has runprivate const string AuthorizationMiddlewareInvokedWithEndpointKey = "__AuthorizationMiddlewareWithEndpointInvoked";private static readonly object AuthorizationMiddlewareWithEndpointInvokedValue = new object();private readonly RequestDelegate _next;private readonly IAuthorizationPolicyProvider _policyProvider;public AuthorizationMiddleware(RequestDelegate next, IAuthorizationPolicyProvider policyProvider){_next = next ?? throw new ArgumentNullException(nameof(next));_policyProvider = policyProvider ?? throw new ArgumentNullException(nameof(policyProvider));}public async Task Invoke(HttpContext context){if (context == null){throw new ArgumentNullException(nameof(context));}var endpoint = context.GetEndpoint();if (endpoint != null){context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue;}var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);if (policy == null){await _next(context);return;}var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);// Allow Anonymous skips all authorizationif (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null){await _next(context);return;}// Note that the resource will be null if there is no matched endpointvar authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource: endpoint);if (authorizeResult.Challenged){if (policy.AuthenticationSchemes.Any()){foreach (var scheme in policy.AuthenticationSchemes){await context.ChallengeAsync(scheme);}}else{await context.ChallengeAsync();}return;}else if (authorizeResult.Forbidden){if (policy.AuthenticationSchemes.Any()){foreach (var scheme in policy.AuthenticationSchemes){await context.ForbidAsync(scheme);}}else{await context.ForbidAsync();}return;}await _next(context);}
}

进行代码分解:

  1. 拿到当前请求的的终结点

  var endpoint = context.GetEndpoint();
  1. 在当前请求拿到终结点endpoint的时候,会通过终结点拿到关联的IAuthorizeData集合

var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();
  1. 将根据IAuthorizeData集合调用AuthorizationPolicy.CombineAsync()来创建组合策略(具体了可以看一下上一章)   ( 用例:[Authorize(Policy = "BaseRole")]  )

var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);
  1. IPolicyEvaluator获取策略评估器对得到的组合策略进行身份验证,多种身份验证得到的用户证件信息会合并进HttpContext.User

 var policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>();var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);
  1. 当使用[AllowAnonymous]的时候,则直接跳过授权检验。 

 if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null){await _next(context);return;}
  1. IPolicyEvaluator提供的AuthorizeAsync授权检查方法,进行策略授权检查。

 var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult, context, resource: endpoint);
  1. 当进行授权时,遍历策略所有的身份验证方案,进行质询,若策略里木有身份验证方案则使用默认身份验证方案进行质询。

当授权评估拒绝就直接调用身份验证方案进行拒绝。

 if (authorizeResult.Challenged){if (policy.AuthenticationSchemes.Any()){foreach (var scheme in policy.AuthenticationSchemes){await context.ChallengeAsync(scheme);}}else{await context.ChallengeAsync();}return;}
else if (authorizeResult.Forbidden)
{if (policy.AuthenticationSchemes.Any()){foreach (var scheme in policy.AuthenticationSchemes){await context.ForbidAsync(scheme);}}else{await context.ForbidAsync();}return;
}

整个过程中,授权中间件会调用授权服务IAuthorizationService来进行授权处理

五、总结

  1. 通过对上述的处理流程的分析,可以看出授权主要是通过IAuthorizationService来实现的,而我们进行使用只需要提供授权策略的Requirement,非常方便灵活的使用。

  2. 从源码权限设计来看,系统注册了各种服务,实现多种默认服务,加上默认的处理方式也满足了大部分应用需求, 所以可以看出这一块的功能还是很强大的,就算我们想通过自定义的方式来实现,也可以通过某些接口来实现拓展。

  3. 其中有很多核心源码怕说的不够清楚,所以在平时的开发项目中,再去看官方文档或源码这样理解应该更容易。

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

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

往期精彩回顾

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

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

相关文章

Iterator(迭代器)--对象行为模式

Iterator&#xff08;迭代器&#xff09;–对象行为模式 一、意图 提供一种方法顺序访问一个聚合对象的各个元素&#xff0c;而又不需暴露该对象的内部结构。 二、动机 1.在软件构建过程中&#xff0c;集合对象内部结构常常变化各异。但对于这些集合对象&#xff0c;我们希望…

Blazor带我重玩前端(三)

VS自带的Blazor模板介绍需要升级VS2019以及.NET Core到最新版&#xff08;具体的最低支持&#xff0c;我已经忘了&#xff0c;总是越新支持的就越好&#xff09;&#xff0c;以更好的支持自己开发Blazor项目。使用VS创建Blazor WebAssembly项目搜索Blazor模板选择Blazor WebAss…

[mybatis]Configuration XML_environments

enviroments transactionManager There are two TransactionManager types (i.e. type"[JDBC|MANAGED]") that are included with MyBatis: • JDBC – This configuration simply makes use of the JDBC commit and rollback facilities directly. It relies on the…

Mediator(中介者)--对象行为型模式

Mediator&#xff08;中介者&#xff09;–对象行为型模式 一、意图 用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显示地相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互。 二、动机 1.在软件构建过程中&#xff0c;经常…

[mybatis]Configuration XML_mappers

mappers 将sql映射注册到全局配置中 mapper 注册一个sql映射 resource:引用类路径下的sql映射文件url:引用网络路径或者磁盘路径下的sql映射文件class:引用(注册)接口 1.有sql映射文件&#xff0c;映射文件名必须和接口同名&#xff0c;并且放在与接口同一目录下&#xff1b;…

Memento(备忘录)--对象行为型模式

Memento&#xff08;备忘录&#xff09;–对象行为型模式 一、意图 在不破坏封装性的前提下&#xff0c;捕获一个对象的内部状态&#xff0c;并在该对象之外保持这个状态。这样以后就可将该对象恢复到原先保存的状态。 二、动机 1.在软件构建过程中&#xff0c;某些对象的状态…

IBM、甲骨文、CNCF 就谷歌对 Istio 治理的处理提出抗议

近日来 Istio 商标转让、IBM 抗议谷歌违背承诺未将 Istio 捐献给 CNCF 的事情闹的沸沸扬扬。Google 宣布将 Istio 商标转让给 Open Usage Commons 组织IBM 声明对 Google 违背承诺未将 Istio 贡献给 CNCF 表示失望下面是据 TheRegister 的报道&#xff1a;谷歌创建了一个开放使…

Observer(观察者)--对象行为型模式

Observer&#xff08;观察者&#xff09;–对象行为型模式 一、意图 定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生变化时&#xff0c;所有的依赖于它的对象都得到通知并被自动更新。 二、动机 1.在软件构建过程中&#xff0c;我们需要为某些对象建立一…

【今天下午活动】从 HelloWorld 到 AntDesign,Blazor 将 .NET 带到现代前端圈

Blazor 是一个 Web UI 框架&#xff0c;可通过 WebAssembly 在任意浏览器中运行 .Net 。Blazor 旨在简化快速的单页面 .Net 浏览器应用的构建过程&#xff0c;它虽然使用了诸如 CSS 和 HTML 之类的 Web 技术&#xff0c;但它使用 C&#xff03;语言和 Razor 语法代替 JavaScrip…

[mybatis]sqlSessionFactory.openSession()

第一个是不会自动提交的 第二个带参数的是会自动提交的

State(状态)--对象行为型模式

State&#xff08;状态&#xff09;–对象行为型模式 一、意图 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。 二、动机 1.在软件构建过程中&#xff0c;某些对象的状态如果改变&#xff0c;其行为也会随之而发生变化&#xff0c;比如文档处于只…

推荐一个Asp.Net Core工具库

Masuit.Tools开源地址https://github.com/XiLife-OSPC/Masuit.Tools包含一些常用的操作类&#xff0c;大都是静态类&#xff0c;加密解密&#xff0c;反射操作&#xff0c;硬件信息&#xff0c;字符串扩展方法&#xff0c;日期时间扩展操作&#xff0c;大文件拷贝&#xff0c;图…

Strategy(策略)--对象行为型模式

Strategy&#xff08;策略&#xff09;–对象行为型模式 一、意图 定义一系列的算法&#xff0c;把它们一个个封装起来&#xff0c;并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。 二、动机 1.在软件构建过程中&#xff0c;某些对象使用的算法可能多种多…

12个Visual Studio调试效率技巧

在这篇文章中&#xff0c;我们假定读者了解VS基本的调试知识&#xff0c;如&#xff1a;F5 开始使用调试器运行程序F9 在当前行设置断点F10 运行到下一个断点处F5 从被调试的已停止程序恢复执行F11 步进到函数内&#xff08;如果当前程序指针指向一个函数&#xff09;F10 步过函…

Template Method(模板方法)--类行为型模式

Template Method&#xff08;模板方法&#xff09;–类行为型模式 一、意图 定义一个操作中的算法的骨架&#xff0c;而将一些步骤延迟到子类中。TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。 二、动机 1.在软件构建过程中&#xff0c;对…

骚年快答 | 微服务架构中的BFF到底是啥?

【答疑解惑】| 作者 / Edison Zhou这是恰童鞋骚年的第263篇原创内容昨天的骚年快答《技术中台与业务中台都是啥玩意》一文中留下一个问题&#xff1a;BFF是啥&#xff1f;为啥在API网关和业务中台之间加入了一层BFF&#xff1f;考虑到在实际工作中&#xff0c;我的大部分同事都…

Visitor(访问者)--对象行为型模式

Visitor&#xff08;访问者&#xff09;–对象行为型模式 一、意图 表示一个作用于某个对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。 二、动机 1.在软件构建过程中&#xff0c;由于需求的改变&#xff0c;某些类层次结构中常…

骚年快答 | 技术中台与业务中台都是啥?

【答疑解惑】| 作者 / Edison Zhou这是恰童鞋骚年的第262篇原创内容最近有童鞋在我之前发布的《聊聊中台》一文中提问&#xff1a;技术中台是什么&#xff1f;和业务中台又有什么区别&#xff1f;考虑到在工作中&#xff0c;也有部分同事问过这个问题&#xff0c;我这里总结一下…

[mybatis]映射文件_参数处理_#和$取值区别

#{}&#xff1a;可以获取map中的值或者pojo对象属性的值${}&#xff1a;可以获取map中的值或者pojo对象属性的值 区别&#xff1a; #{}&#xff1a;是以预编译的形式&#xff0c;将参数设置到sql语句中&#xff0c;相当于原生jdbc的PreparedStatement&#xff1b;防止sql注入${…