ASP.NET 核心身份中的分层政策/要求

Hierarchical policies / requirements in ASP.NET Core Identity

我刚刚开始使用 ASP.NET Core Identity 并定义了以下要求:

public sealed class IsCustomerUserRequirement : IAuthorizationRequirement

public sealed class IsSuperUserRequirement : IAuthorizationRequirement

使用以下基本处理程序:

public class IsCustomerUserHandler : AuthorizationHandler<IsCustomerUserRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsCustomerUserRequirement requirement)
    {
        if (context.User.HasClaim(_ => _.Type == "customer"))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

public class IsSuperUserHandler : AuthorizationHandler<IsSuperUserRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsSuperUserRequirement requirement)
    {
        if (context.User.IsInRole("super_user"))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

然后我可以将这些放在基本政策中:

        services
            .AddAuthorization(options =>
            {
                options.AddPolicy("MustBeSuperUser", policy => policy.Requirements.Add(new IsSuperUserRequirement()));
                options.AddPolicy("CustomersOnly", policy => policy.Requirements.Add(new IsCustomerUserRequirement()));
            });

并使用 [Authorize("CustomersOnly")] 应用它,效果很好。

我的要求 是能够允许超级用户,声明具有 super_user 角色但 没有 customer 声明,也可以访问仅限客户的区域。

我目前通过将处理程序更改为手动检查来实现此功能:

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IsCustomerUserRequirement requirement)
    {
        if (context.User.HasClaim(_ => _.Type == Claims.Customer) ||
            context.User.IsInRole(Roles.SuperUser))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }

我的问题 感觉我没抓住重点。有没有更好的方法来定义它,这样我以后就不必在每个处理程序中重复超级用户检查了?


所有这一切的大局是我使用IdentityServer4(ASP.NET Identity-backed)进行身份验证,然后打算使用一些基于JWT的声明(一个声明,两个角色)来进一步识别用户授权落入应用程序-特定的角色/权限结构和一些与 Identity Server 无关的自定义中间件。围绕该主题有哪些最佳实践(如果有)?

“这感觉好像我没抓住要点” – 是的,在某种程度上你没抓住要点。您正在进行基于角色的授权:用户可以是客户或超级用户。

但是,新模型是基于声明的授权,其中用户对某事有声明,而您正在使用它来授权他们。因此,理想情况下,超级用户将获得与客户相同的声明,并被允许以这种方式访问​​资源。这样的声明也不会被称为 customer,而是用户的 属性。

您仍然可以使用带有声明的基于角色的授权模型,但您应该避免混合它们。正如您自己注意到的那样,这最终会变得有点奇怪。

话虽这么说,有多种方法可以使用不同的要求使政策成功。如果您只使用角色(而不是 customer 声明),您可以简单地使用内置方式:

options.AddPolicy("MustBeSuperUser", policy => policy.RequireRole("super_user"));
options.AddPolicy("CustomersOnly", policy => policy.RequireRole("customer", "super_user"));

这样,CustomersOnly 策略将由 customersuper_user 角色执行。

由于您没有为客户使用角色,因此您必须在此处遵循您的要求实施。授权要求的工作方式是,对于同一要求类型,您可以有多个处理程序,并且只有其中一个需要成功(只要 none 失败 )即可满足要求成功。

因此您可以让 IsSuperUserHandler 处理多个需求。您可以按照 AuthorizationHandler<T> 实施来完成这项工作:

public class IsSuperUserHandler : IAuthorizationHandler
{
    public virtual async Task HandleAsync(AuthorizationHandlerContext context)
    {
        foreach (var req in context.Requirements)
        {
            if (req is IsSuperUserRequirement || req is IsCustomerUserRequirement)
            {
                if (context.User.IsInRole("super_user"))
                    context.Succeed(req);
            }
        }
    }
}

因此您的 IsSuperUserHandler 现在是 IsSuperUserRequirementIsCustomerUserRequirement 的授权处理程序。因此,需要 IsCustomerUserRequirementCustomersOnly 政策也将为超级用户实现。