本文介绍了ASP.NET核心授权:组合或要求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不确定如何在ASP.NET核心授权中实现组合的"OR"要求。在以前的ASP.NET版本中,这将通过角色来完成,但我正在尝试使用声明来完成这一点,部分原因是为了更好地理解它。

用户有一个名为AcCountType的枚举,它将提供对控制器/操作等的不同级别的访问。有三个级别的类型,称为User、BiggerUser和BigsterUser。因此,BigsterUser可以访问他们下面的帐户类型拥有的所有内容,依此类推。我希望通过使用策略的授权标记来实现这一点。

所以首先我有一个要求:

public class TypeRequirement : IAuthorizationRequirement
{
    public TypeRequirement(AccountTypes account)
    {
        Account = account;
    }

    public AccountTypes Account { get; }
}

我创建策略:

services.AddAuthorization(options =>
{
    options.AddPolicy("UserRights", policy => 
        policy.AddRequirements(new TypeRequirement(AccountTypes.User));
});

通用处理程序:

public class TypeHandler : AuthorizationHandler<TypeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TypeRequirement requirement)
    {
        if (!context.User.HasClaim(c => c.Type == "AccountTypes"))
        { 
            context.Fail();
        }

        string claimValue = context.User.FindFirst(c => c.Type == "AccountTypes").Value;
        AccountTypes claimAsType = (AccountTypes)Enum.Parse(typeof(AccountTypes), claimValue);
        if (claimAsType == requirement.Account)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

我要做的是向策略添加多个要求,以便任何都可以满足它。但我目前的理解是,如果我这样做:

options.AddPolicy("UserRights", policy => policy.AddRequirements(
    new TypeRequirement(AccountTypes.User),
    new TypeRequirement(AccountTypes.BiggerUser)
);

这两个要求都必须满足。如果AddRequirements中有指定OR条件的方法,我的处理程序就会工作。那么,我是在正确的轨道上,还是有其他更有意义的方式来实现这一点?

推荐答案

当您要实现OR逻辑时,官方文档有一个dedicated section。他们提供的解决方案是根据一个需求注册多个授权处理程序。在这种情况下,所有处理程序都会运行,如果至少有一个处理程序成功,则认为满足了要求。

不过,我认为该解决方案不适用于您的问题;我认为有两种方法可以很好地实现这一点


TypeRequirement中提供多个AccountTypes

然后,该要求将包含满足该要求的所有值。

public class TypeRequirement : IAuthorizationRequirement
{
    public TypeRequirement(params AccountTypes[] accounts)
    {
        Accounts = accounts;
    }

    public AccountTypes[] Accounts { get; }
}

然后处理程序验证当前用户是否与定义的帐户类型之一匹配

public class TypeHandler : AuthorizationHandler<TypeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TypeRequirement requirement)
    {

        if (!context.User.HasClaim(c => c.Type == "AccountTypes"))
        { 
            context.Fail();
            return Task.CompletedTask;
        }

        string claimValue = context.User.FindFirst(c => c.Type == "AccountTypes").Value;
        AccountTypes claimAsType = (AccountTypes)Enum.Parse(typeof(AccountTypes),claimValue);
        if (requirement.Accounts.Any(x => x == claimAsType))
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}

这允许您创建多个使用相同要求的策略,但您可以为每个策略定义AccountTypes的有效值

options.AddPolicy(
    "UserRights",
    policy => policy.AddRequirements(new TypeRequirement(AccountTypes.User, AccountTypes.BiggerUser, AccountTypes.BiggestUser)));

options.AddPolicy(
    "BiggerUserRights",
    policy => policy.AddRequirements(new TypeRequirement(AccountTypes.BiggerUser, AccountTypes.BiggestUser)));

options.AddPolicy(
    "BiggestUserRights",
    policy => policy.AddRequirements(new TypeRequirement(AccountTypes.BiggestUser)));

使用枚举比较功能

如您在问题中所说,您处理AccountTypes的不同值的方式有一个层次

  • User可以访问某些内容;
  • BiggerUser可以访问User可以访问的所有内容,外加一些其他内容;
  • BiggestUser可以访问所有内容

其想法是,需求将定义满足AccountTypes所需的最低值,然后处理程序将其与用户的帐户类型进行比较。

枚举可以与<=>=运算符进行比较,也可以使用CompareTo方法进行比较。我无法快速找到有关此问题的可靠文档,但this code sample on docs.microsoft.com显示了小于或等于运算符的用法。

要利用此功能,枚举值需要与您期望的层次结构匹配,如下所示:

public enum AccountTypes
{
    User = 1,
    BiggerUser = 2,
    BiggestUser = 3
}

public enum AccountTypes
{
    User = 1,
    BiggerUser, // Automatiaclly set to 2 (value of previous one + 1)
    BiggestUser // Automatically set to 3
}

需求、处理程序和策略声明的代码将如下所示:

public class TypeHandler : AuthorizationHandler<TypeRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, TypeRequirement requirement)
    {

        if (!context.User.HasClaim(c => c.Type == "AccountTypes"))
        { 
            context.Fail();
            return Task.CompletedTask;
        }

        string claimValue = context.User.FindFirst(c => c.Type == "AccountTypes").Value;
        AccountTypes claimAsType = (AccountTypes)Enum.Parse(typeof(AccountTypes),claimValue);
        if (claimAsType >= requirement.MinimumAccount)
        {
            context.Succeed(requirement);
        }

        return Task.CompletedTask;
    }
}
options.AddPolicy(
    "UserRights",
    policy => policy.AddRequirements(new TypeRequirement(AccountTypes.User)));

options.AddPolicy(
    "BiggerUserRights",
    policy => policy.AddRequirements(new TypeRequirement(AccountTypes.BiggerUser)));

options.AddPolicy(
    "BiggestUserRights",
    policy => policy.AddRequirements(new TypeRequirement(AccountTypes.BiggestUser)));

这篇关于ASP.NET核心授权:组合或要求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 18:02