回顧:基於.NetCore3.1系列 —— 認證受權方案之受權揭祕 (上篇)html
在上一篇中,主要講解了受權在配置方面的源碼,從添加受權配置開始,咱們引入了須要的受權配置選項,而不一樣的受權要求構建不一樣的策略方式,從而實現一種本身滿意的受權需求配置要求。git
在這一節中,繼續上一篇的內容往下深刻了解受權內部機制的奧祕以及是如何實現執行受權流程的。github
在上一篇中,咱們經過定義受權策略,查看源碼發現,在對受權配置AuthorizationOptions
以後,受權系統經過DI的方式註冊了幾個核心的默認實現。c#
以前咱們進行對步驟一的受權有了大概瞭解,因此下面咱們將對步驟二進行的註冊對象進行說明。app
受權服務接口,用來肯定受權是否成功的主要服務,接口的定義爲asp.net
public interface IAuthorizationService { Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, IEnumerable<IAuthorizationRequirement> requirements); Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object resource, string policyName); }
兩個接口的參數不一樣之處在於IAuthorizationRequirement
和policyName
,分別是指定資源的一組特定要求和指定的受權名稱。async
同時asp.net core還爲IAuthorizationService
接口拓展了幾個方法:ide
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); } }
經過上面的代碼能夠發現,在對象實例中,經過構造函數的方式分別注入了IAuthorizationPolicyProvider
、IAuthorizationHandlerProvider
、IAuthorizationEvaluator
、IAuthorizationHandlerContextFactory
這幾個核心服務,以及配置選項的AuthorizationOptions對象,再經過實現的方法AuthorizeAsync
能夠看出,在方法中調用GetPolicyAsync
來獲取Requirements
,具體的能夠看一下上一節的AuthorizationPolicy,然後在根據受權上下文來判斷。
這裏就用到了注入的幾個核心對象來實現完成受權的。下面會分別介紹到的。
由上面的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
字典中,由上代碼能夠發現這字典的用處。
先看看這個接口的源代碼
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
中的方法,能夠根據受權上下文獲取到請求調用的處理程序。
這個是接口的方法,做用是獲取全部的受權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
由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。
其中的AuthorizationResult
和AuthorizationFailure
分別爲
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
來完成校驗返回的結果。
接口方式實現,判斷是否受權,實現此接口的類
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又是如何執行的呢?
咱們能夠發現,IAuthorizationHandler
在AddAuthorization
拓展方法中能夠看到默認註冊了一個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
方法被執行的時候,它會從AuthroizationHanderContext
的Requirements
屬性中提取全部的IAuthoizationHandler
對象,並逐個調用它們的HandleAsync
方法來實施受權檢驗。
因此能夠看到的出,PassThroughAuthorizationHandler
是一個特殊而且重要的受權處理器類型,其特殊之處在於它並無實現針對某個具體規則的受權檢驗,可是AuthorizationHandlerContext上下文全部的IAuthorizationHandler
都是經過該對象驅動執行的。
接口的方式實現,爲特定需求類型調用的受權處理程序的基類
public interface IPolicyEvaluator { Task<AuthenticateResult> AuthenticateAsync(AuthorizationPolicy policy, HttpContext context); Task<PolicyAuthorizationResult> AuthorizeAsync(AuthorizationPolicy policy, AuthenticateResult authenticationResult, HttpContext context, object resource); }
定義了兩個方法AuthenticateAsync
和AuthorizeAsync
方法
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 challenge return (authenticationResult.Succeeded) ? PolicyAuthorizationResult.Forbid() : PolicyAuthorizationResult.Challenge(); } }
受權中間件委託它來實現身份驗證和受權處理,它內部會調用AuthorizationService,進而執行全部受權處理器AuthorizationHandler, (在後面會提到受權中間件用到這兩個方法)
當受權策略沒有設置AuthenticationSchemes,則只判斷下當前請求是否已作身份驗證,若作了就返回成功
當受權策略設置了AuthenticationSchemes,則遍歷身份驗證方案逐個進行身份驗證處理 。
其中context.User
就是使用context.AuthenticateAsync(DefaultAuthenticateScheme)
來賦值的,將全部獲得的用戶標識重組成一個複合的用戶標識。
當咱們但願使用非默認的Scheme,或者是想合併多個認證Scheme的Claims時,就須要使用基於Scheme的受權來重置Claims了。
它的實現也很簡單,直接使用咱們在受權策略中指定的Schemes來依次調用認證服務的
AuthenticateAsync
方法,並將生成的Claims合併,最後返回咱們熟悉的AuthenticateResult
認證結果。
該方法會根據Requirements來完成受權,具體的實現是經過調用IAuthorizationService
調用AuthorizeAsync
來實現的。
最終返回的是一個PolicyAuthorizationResult
對象,並在受權失敗時,根據認證結果來返回Forbid(未受權)
或Challenge(未登陸)
。
以上彙總
- 受權服務IAuthorizationService,接口的默認實現爲DefaultAuthorizationService,進行受權驗證。
- 在會根據受權策略提供器
IAuthorizationPolicyProvider
來獲取指定名稱的受權。- 經過受權處理器上下文對象工廠IAuthorizationHandlerContextFactory受權處理器AuthorizationHandler在受權時須要傳入AuthorizationHandlerContext(上面說了受權完成後的結果也存儲在裏面)。因此在執行受權處理器以前須要構建這個上下文對象,就是經過這個工廠構建的,主要的數據來源就是 當前 或者 指定的 受權策略AuthorizationPolicy。
- 因此這個時候會受權處理提供其 IAuthorizationHandlerProvider,來獲取系統中全部受權處理器。
- 受權評估器IAuthorizationEvaluator來肯定受權結果是否成功,在受權處理器AuthorizationHandler在執行完受權後,結果是存儲在AuthorizationHandlerContext中的,這裏的評估器只是根據AuthorizationHandlerContext建立一個受權結果AuthorizationResult。
- 上面所說的受權處理器就是IAuthorizationHandler,處理器中包含主要的受權邏輯,在處理的過程當中會將全部的受權處理器一一驗證。
- 因此在受權中間件中會利用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 run private 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 authorization if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null) { await _next(context); return; } // Note that the resource will be null if there is no matched endpoint var 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); } }
進行代碼分解:
var endpoint = context.GetEndpoint();
endpoint
的時候,會經過終結點拿到關聯的IAuthorizeData
集合var authorizeData = endpoint?.Metadata.GetOrderedMetadata<IAuthorizeData>() ?? Array.Empty<IAuthorizeData>();
IAuthorizeData
集合調用AuthorizationPolicy.CombineAsync()來建立組合策略(具體了能夠看一下上一章) ( 用例: [Authorize(Policy = "BaseRole")] )var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData);
IPolicyEvaluator
獲取策略評估器對獲得的組合策略進行身份驗證,多種身份驗證獲得的用戶證件信息會合並進HttpContext.Uservar policyEvaluator = context.RequestServices.GetRequiredService<IPolicyEvaluator>(); var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context);
[AllowAnonymous]
的時候,則直接跳過受權檢驗。if (endpoint?.Metadata.GetMetadata<IAllowAnonymous>() != null) { await _next(context); return; }
IPolicyEvaluator
提供的AuthorizeAsync
受權檢查方法,進行策略受權檢查。var 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; }
整個過程當中,受權中間件會調用受權服務IAuthorizationService
來進行受權處理
IAuthorizationService
來實現的,而咱們進行使用只須要提供受權策略的Requirement,很是方便靈活的使用。