ASP.NET核心标识中的分层策略/要求

时间:2017-10-25 11:48:36

标签: c# asp.net-core-identity

我刚开始使用ASP.NET核心标识并定义了以下要求:

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角色的主体但没有 {{ 1}}声明,也可以访问仅限客户的区域。

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

customer

我的问题 这就像我错过了这一点。有没有更好的方法来定义这个,所以我不必在将来重复每个处理程序中的超级用户检查?

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

1 个答案:

答案 0 :(得分:3)

“感觉就像我错过了这一点” - 是的,在某种程度上你忽略了这一点。您正在进行基于角色的授权:用户可以是客户或超级用户。

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

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

话虽如此,有多种方法可以使用不同的要求来成功实施政策。如果您仅使用角色(而不是customer声明),则可以使用内置方式:

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

这样,CustomersOnlycustomer角色都会实现super_user政策。

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

因此,您可以让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的授权处理程序。因此,超级用户也将履行需要CustomersOnly的{​​{1}}政策。