我在ASP.NET Core应用程序中设置了一个标准身份验证系统。
用户、角色、角色声明(充当权限)
在Startup.cs中,我为每个角色和每个权限创建了一个策略。假设这将使我在视图中具有充分的灵活性,可以说我希望此按钮显示用户是否是具有DeleteCustomer声明的角色的一部分,或者用户是否属于角色Superuser。
如何使用Authorize属性执行OR条件。例如,在我的整个网站上,我希望SuperuserRole Policy对所有内容都拥有完全权限。
在一个操作方法上,让我们假设我有以下内容:
[授权(策略="编辑客户")]
这需要将登录用户分配给具有声明的角色:Edit.Customer,因为我正在为声明Edit.Customer.创建策略。这一切都很好,但我如何说我希望任何具有角色超级用户的用户都能够访问EditCustomer操作方法。超级用户作为角色在数据库中,并作为名为RequireSuperUser的策略添加。
您可以在Startup.cs:中添加OR条件
services.AddAuthorization(options => {
options.AddPolicy("EditCustomer", policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(c => (c.Type == "DeleteCustomer" || c.Type == "Superuser"))));
});
我也面临着类似的问题,我只想让"John Doe"、"Jane Doe"用户查看"Ending Contracts"屏幕,或者只希望"MIS"部门的任何人也能访问同一屏幕。以下对我有效,我有索赔类型"部门"one_answers"用户名":
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)))));
});
您可以使用两个不同的AuthorizationHandler
处理程序来满足IAuthorizationRequirement
:的相同要求
public class FooOrBooRequirement : IAuthorizationRequirement { }
public class FooHandler : AuthorizationHandler<FooOrBooRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationContext context, FooOrBooRequirement requirement)
{
if (context.User.HasClaim(c => c.Type == "Foo" && c.Value == true))
{
context.Succeed(requirement);
return Task.FromResult(0);
}
}
}
public class BooHandler : AuthorizationHandler<FooOrBooRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationContext context, FooOrBooRequirement requirement)
{
if (context.User.HasClaim(c => c.Type == "Boo" && c.Value == true))
{
context.Succeed(requirement);
return Task.FromResult(0);
}
}
}
因此,在AddPolicy
中,FooHandler
或BooHandler
:只能满足一个要求
services.AddAuthorization(authorizationOptions =>
{
authorizationOptions.AddPolicy(
"MustBeFooOrBoo",
policyBuilder =>
{
policyBuilder.RequireAuthenticatedUser();
policyBuilder.AddRequirements(new FooOrBooRequirement());
});
});
请注意,AuthorizationHandler
提供了一个更强大的自定义策略,因此它只与需要更复杂身份验证的特殊情况最相关,例如,如果您想确定用户是否是资源所有者。
对于一个简单的基于索赔的政策,我建议使用@richardmneyan的答案。
我们可以向AuthorizationHandler
注入DBContext(如果使用EF,或者如果不使用用户存储库)或HttpContextAccessor来实现这一点。
通过注入EF上下文(或用户存储库),我们可以查询数据库以确定当前用户是否是超级用户。
或者通过注入HttpContextAccessor
,我们可以从中确定用户是否是超级用户。这种方法比第一种方法更快,但取决于用户上下文是否具有所需的信息。
为了实现这一点,假设您拥有EditCustomerRequirement
和EditCustomerAuthorizationHandler
:
public class EditCustomerAuthorizationHandler: AuthorizationHandler<EditCustomerRequirement>
{
readonly AppDbContext _context;
readonly IHttpContextAccessor _contextAccessor;
public EditCustomerAuthorizationHandler(DbContext c, IHttpContextAccessor ca)
{
_context = c;
_contextAccessor = ca;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, EditCustomerRequirement requirement)
{
//here we have the access to DB and HttpContext
//we can get the information if the user is superuser from either db or httpContext
var isSuperUser = await IsSuperUser(_context);
//or
var isSuperUser = IsSuperUser(_contextAccessor);
if(isSuperUser)
{
context.Succeed(requirement);
}
else
{
//the current implementation of EditCustomer Policy
}
}
}
IsSuperUser
是我们可以从db上下文或http上下文中获取信息的某种方法。