Asp.Net Core中的帐户角色框架(6)

上一篇分析了IPolicyEvaluator.AuthenticateAsync的过程,今天继续:

IPolicyEvaluator.AuthorizeAsync,判断权限的过程

补记录,AuthorizationMiddleware.Invoke方法中,在完成IPolicyEvaluator.AuthenticateAsync后,继续判断是否匿名,如果是的话,直接交给下一个中间件,如果不是,继续执行IPolicyEvaluator.AuthorizeAsync,其代码如下。

        // 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;
        }

policyEvaluator.AuthorizeAsync(policy, authenticateResult!, context, resource);

A、IAuthorizationService(实现类DefaultAuthorizationService).AuthorizeAsync

方法入口参数:

public virtual async Task<AuthorizationResult> AuthorizeAsync(ClaimsPrincipal user, object? resource, IEnumerable<IAuthorizationRequirement> requirements)

B、创建AuthorizationHandlerContext

通过 IAuthorizationHandlerContextFactory.CreateContext创建

C、获得本次权限验证类相关的 IAuthorizationHandler实现类集合

通过 IAuthorizationHandlerProvider(默认实现类 DefaultAuthorizationHandlerProvider).GetHandlersAsync 获得

D、遍历计算权限验证各种规则,如果配置中InvokeHandlersAfterFailure为False,则有一个失败,立刻跳出遍历,否则每一条规则都需要进行验证

遍历 IAuthorizationHandler集合,对每一个实现了AuthorizationHandler子类,执行其HandleAsync,实际执行HandleRequirementAsync方法

E、以RolesAuthorizationRequirement为例,代码如下,判断需要的Role在用户自身Role中是否存在,如果存在,就是Succeed。

    /// <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 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;
    }

F、判断结束,根据规则结果来计算成功失败

执行 IAuthorizationEvaluator(默认实现类DefaultAuthorizationEvaluator)下的Evaluate方法。

其基于 AuthorizationHandlerContext 中的 HasSucceeded 或 HasFailed 来判断

如果成功,则返回 PolicyAuthorizationResult.Success()

如果失败,则需要看上一篇身份验证那里的结果。

身份验证失败,则返回 PolicyAuthorizationResult.Challenge , 转入身份验证页面。

身份验证成功,则返回 PolicyAuthorizationResult.Forbid , 转入权限不足页面。