在 ASP.NET Core Identity 中使用 Authorize 属性检查多个策略之一
Posted
技术标签:
【中文标题】在 ASP.NET Core Identity 中使用 Authorize 属性检查多个策略之一【英文标题】:Checking for one of multiple policies with Authorize attribute in ASP.NET Core Identity 【发布时间】:2017-11-09 18:51:37 【问题描述】:我已经在 ASP.NET Core 应用程序中设置了标准身份验证系统。
用户、角色、角色声明(作为权限)
在 Startup.cs 中,我为每个角色和每个权限创建一个策略。假设这将使我的视图具有完全的灵活性,以便能够说我希望此按钮显示用户是否属于具有声明 DeleteCustomer 的角色的一部分,或者用户是否属于角色超级用户。
如何使用 Authorize 属性执行 OR 条件。例如,在我的整个站点中,我希望 SuperuserRole Policy 拥有对所有内容的完全权限。
在一个动作方法上,假设我有以下内容:
[授权(Policy = "EditCustomer")]
这需要将登录用户分配给具有声明:Edit.Customer 的角色,因为我正在为声明 Edit.Customer 创建策略。这一切都很好,但是我怎么说我希望任何具有超级用户角色的用户都能够访问 EditCustomer 操作方法。超级用户作为角色在数据库中,另外添加为名为 RequireSuperUser 的策略。
【问题讨论】:
你得到这个为你工作了吗?我面临着类似的问题。 @Richard Mneyan 的回答得到了我的投票并为我工作。得到这个答案会很好,因为它会帮助其他人。 【参考方案1】:您可以在 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”用户查看“结束合同”屏幕或仅来自“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)))));
);
【讨论】:
太棒了,谢谢!对于登陆此处并针对 Azure 角色进行身份验证的任何人,都可以使用以下内容:policy.RequireAssertion(context => context.User.HasClaim(ClaimTypes.Role, "Analyst") || context.User.HasClaim(ClaimTypes.Role, "阅读器"))【参考方案2】:您可以使用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
提供了更强大的自定义策略,因此它仅适用于需要更复杂身份验证的特殊情况,例如,如果您想确定用户是否是资源所有者。
对于仅基于索赔的简单政策,我建议使用@richard-mneyan 的答案。
【讨论】:
这对我来说非常有用,谢谢! 嘿@MattG,很高兴我能帮上忙【参考方案3】:我们可以将 DBContext(如果使用 EF,或者如果不使用用户存储库)或 HttpContextAccessor 注入到AuthorizationHandler
来实现这一点。
通过注入 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 上下文中获取信息的方法。
【讨论】:
以上是关于在 ASP.NET Core Identity 中使用 Authorize 属性检查多个策略之一的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET CORE 5.0 Identity 显示当前登录用户
Asp.Net core MVC6如何在Identity 3中初始添加角色
如何按照存储库模式在 Asp.Net Core 5.0 项目上实现 .Net Core Identity?