/// <summary> /// A middleware that enables authorization capabilities. /// </summary> public class AuthorizationMiddleware { // AppContext switch used to control whether HttpContext or endpoint is passed as a resource to AuthZ private const string SuppressUseHttpContextAsAuthorizationResource = "Microsoft.AspNetCore.Authorization.SuppressUseHttpContextAsAuthorizationResource"; // 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; /// <summary> /// Initializes a new instance of <see cref="AuthorizationMiddleware"/>. /// </summary> /// <param name="next">The next middleware in the application middleware pipeline.</param> /// <param name="policyProvider">The <see cref="IAuthorizationPolicyProvider"/>.</param> public AuthorizationMiddleware(RequestDelegate next, IAuthorizationPolicyProvider policyProvider) { _next = next ? ? throw new ArgumentNullException(nameof(next)); _policyProvider = policyProvider ? ? throw new ArgumentNullException(nameof(policyProvider)); } /// <summary> /// Invokes the middleware performing authorization. /// </summary> /// <param name="context">The <see cref="HttpContext"/>.</param> public async Task Invoke(HttpContext context) { if(context == null) { throw new ArgumentNullException(nameof(context)); } //mvc控制器路由 var endpoint = context.GetEndpoint(); if(endpoint != null) { // EndpointRoutingMiddleware uses this flag to check if the Authorization middleware processed auth metadata on the endpoint. // The Authorization middleware can only make this claim if it observes an actual endpoint. context.Items[AuthorizationMiddlewareInvokedWithEndpointKey] = AuthorizationMiddlewareWithEndpointInvokedValue; } // IMPORTANT: Changes to authorization logic should be mirrored in MVC's AuthorizeFilter //获取标签 AuthorizeAttribute 中的数据 转化为 IAuthorizeData var authorizeData = endpoint ? .Metadata.GetOrderedMetadata <IAuthorizeData> () ? ? Array.Empty < IAuthorizeData > (); //根据setup.cs 配置的 services.AddAuthorization(options.AddPolicy("Book", policy =>{ policy.Requirements.Add(new BookRequirment());})); //如果一个类上面贴了多个 AuthorizeAttribute ,AuthorizationPolicy.CombineAsync 就会把 Requirements 组合起来 var policy = await AuthorizationPolicy.CombineAsync(_policyProvider, authorizeData); if(policy == null) { await _next(context); return; } // Policy evaluator has transient lifetime so it's fetched from request services instead of injecting in constructor var policyEvaluator = context.RequestServices.GetRequiredService <IPolicyEvaluator> (); var authenticateResult = await policyEvaluator.AuthenticateAsync(policy, context); if(authenticateResult ? .Succeeded ? ? false) { if(context.Features.Get <IAuthenticateResultFeature> () is IAuthenticateResultFeature authenticateResultFeature) { authenticateResultFeature.AuthenticateResult = authenticateResult; } else { var authFeatures = new AuthenticationFeatures(authenticateResult); context.Features.Set < IHttpAuthenticationFeature > (authFeatures); context.Features.Set < IAuthenticateResultFeature > (authFeatures); } } // Allow Anonymous still wants to run authorization to populate the User but skips any failure/challenge handling if(endpoint ? .Metadata.GetMetadata < IAllowAnonymous > () != null) { await _next(context); return; } object ? resource; if(AppContext.TryGetSwitch(SuppressUseHttpContextAsAuthorizationResource, out var useEndpointAsResource) && useEndpointAsResource) { resource = endpoint; } else { resource = context; } var authorizeResult = await policyEvaluator.AuthorizeAsync(policy, authenticateResult!, context, resource); var authorizationMiddlewareResultHandler = context.RequestServices.GetRequiredService <IAuthorizationMiddlewareResultHandler> (); await authorizationMiddlewareResultHandler.HandleAsync(_next, context, policy, authorizeResult); } }
AuthorizationPolicy 对象的数据结构
用于存放endpoint 中设计的 PolicyRequirement 的集合。
/// <summary> /// Gets a readonly list of <see cref="IAuthorizationRequirement"/>s which must succeed for /// this policy to be successful. /// </summary> public IReadOnlyList<IAuthorizationRequirement> Requirements { get; } /// <summary> /// Gets a readonly list of the authentication schemes the <see cref="AuthorizationPolicy.Requirements"/> /// are evaluated against. /// </summary> public IReadOnlyList<string> AuthenticationSchemes { get; }
3 IAuthorizationHandler 的二种方式,
public interface IAuthorizationHandler { /// <summary> /// Makes a decision if authorization is allowed. /// </summary> /// <param name="context">The authorization information.</param> Task HandleAsync(AuthorizationHandlerContext context); }
services.AddSingleton<IAuthorizationHandler, PermissionHandler>();
/// <summary> /// 判断用户是否具有权限 /// </summary> public class PermissionHandler : IAuthorizationHandler { public async Task HandleAsync(AuthorizationHandlerContext context) { } }
第2中方式
AuthorizationHandler<TRequirement> 抽象类实现了 IAuthorizationHandler,HandleAsync 从context 根据不同的类型的 IAuthorizationRequirement 去执行对应的 RequirementHandler
public abstract class AuthorizationHandler<TRequirement> : IAuthorizationHandler where TRequirement : IAuthorizationRequirement { /// <summary> /// Makes a decision if authorization is allowed. /// </summary> /// <param name="context">The authorization context.</param> public virtual async Task HandleAsync(AuthorizationHandlerContext context) { foreach (var req in context.Requirements.OfType<TRequirement>()) { await HandleRequirementAsync(context, req); } } /// <summary> /// Makes a decision if authorization is allowed based on a specific requirement. /// </summary> /// <param name="context">The authorization context.</param> /// <param name="requirement">The requirement to evaluate.</param> protected abstract Task HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement); }
RequirementHandler 仅实现 抽象类的 HandleRequirementAsync(AuthorizationHandlerContext context, TRequirement requirement) 的方法,接收context 参数和 requirement
/// <summary> /// Checks if a user meets a specific set of requirements for the specified resource. /// </summary> /// <param name="user">The user to evaluate the requirements against.</param> /// <param name="resource">The resource to evaluate the requirements against.</param> /// <param name="requirements">The requirements to evaluate.</param> /// <returns> /// A flag indicating whether authorization has succeeded. /// This value is <value>true</value> when the user fulfills the policy otherwise <value>false</value>. /// </returns> public virtual 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); //找到实现IAuthorizationHandler的对象,包含 直接继承 IAuthorizationHandler或者 requirementHandler, 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(result.Failure!); } return result; }
标签:Core,ASP,resource,中间件,policy,context,var,public,authorization From: https://www.cnblogs.com/871735097-/p/17585254.html