我不确定如何实现这一点。在asp.net的早期版本中,这可以用角色完成,但我试图用声明来做,部分是为了更好地理解它。用户有一个名为AccountType的枚举,它将提供对控制器/操作/等的不同级别的访问。有三种类型的类型,称为User,BiggerUser和BiggestUser。所以BiggestUser可以访问他下面的帐户类型等等。我想使用策略通过Authorize标签实现。 所以首先我有一个要求:
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条件,我的处理程序将起作用。我是在正确的轨道上还是有一种不同的方式来实现这一点更有意义?
答案 0 :(得分:1)
当您想要实现 OR 逻辑时,官方文档有dedicated section。他们提供的解决方案是针对一个要求注册多个授权处理程序。在这种情况下,如果至少有一个处理程序成功,则运行所有处理程序并认为满足要求。
我不认为解决方案适用于您的问题;我可以看到两种很好地实现这个的方法
AccountTypes
TypeRequirement
然后,该要求将包含满足要求的所有值。
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)));
答案 1 :(得分:0)
从我的original answer中抄录给那些寻求简短答案的人(注意:以下解决方案无法解决层次结构问题)。
您可以在Startup.cs中添加 OR 条件:
例如我只希望“ John Doe”,“ Jane Doe”用户查看“ Ending Contracts”屏幕,或者仅来自“ MIS”部门的任何人也可以访问同一屏幕。以下内容对我有用,我在其中声明了“部门”和“用户名”的类型:
services.AddAuthorization(options => {
options.AddPolicy("EndingContracts", policy =>
policy.RequireAssertion(context => context.User.HasClaim(c => (c.Type == "department" && c.Value == "MIS" ||
c.Type == "UserName" && "John Doe, Jane Doe".Contains(c.Value)))));
});