使用ASP.NET核心标识中的“授权”属性检查多个策略之一

时间:2017-11-09 18:51:37

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

我已在ASP.NET Core应用程序中设置了标准身份验证系统。

用户,角色,RoleClaims(充当权限)

在Startup.cs中,我为每个角色和每个权限创建一个策略。假设这会让我在视图中具有完全的灵活性,可以说我希望此按钮显示用户是否是声明DeleteCustomer的角色的一部分,或者用户是否属于角色超级用户。

如何使用Authorize属性执行OR条件。例如,在我的整个网站中,我希望SuperuserRole Policy拥有对所有内容的完全权限。

通过动作方法,我想说我有以下内容:

[授权(Policy =“EditCustomer”)]

这将要求已登录的用户被分配到具有声明的角色:Edit.Customer,因为我正在为声明Edit.Customer创建策略。这一切都运行正常,但我怎么说我希望任何具有角色超级用户的用户能够访问EditCustomer操作方法。超级用户作为角色位于数据库中,另外还添加为名为RequireSuperUser的策略。

3 个答案:

答案 0 :(得分:6)

您可以在Startup.cs中添加OR条件:

services.AddAuthorization(options => {
    options.AddPolicy("EditCustomer", policy =>
        policy.RequireAssertion(context => 
        context.User.HasClaim(c => (c.Type == "DeleteCustomer" || c.Type == "Superuser"))));
});

我面临着类似的问题,我只想和#34; 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)))));
});

答案 1 :(得分:0)

您可以使用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中,您只有FooHandlerBooHandler可以满足的一项要求:

services.AddAuthorization(authorizationOptions =>
{
    authorizationOptions.AddPolicy(
        "MustBeFooOrBoo",
        policyBuilder =>
        {
            policyBuilder.RequireAuthenticatedUser();
            policyBuilder.AddRequirements(new FooOrBooRequirement());
        });
});

请注意,AuthorizationHandler提供了更强大的自定义策略,因此它仅与需要更复杂身份验证的特殊情况(例如,如果您要确定用户是否为资源所有者)最相关。

对于仅基于索赔的简单政策,我建议使用@ richard-mneyan的答案。

答案 2 :(得分:0)

我们可以向AuthorizationHandler注入DBContext(如果使用EF或不使用用户存储库)或HttpContextAccessor来实现这一目标。

通过注入EF上下文(或用户存储库),我们可以查询数据库以确定当前用户是否是超级用户。

或者通过注入HttpContextAccessor,我们可以从中确定用户是否是超级用户。这种方法比第一种更快,但是取决于用户上下文是否具有所需的信息。

要实现此目标,请假设您拥有EditCustomerRequirementEditCustomerAuthorizationHandler

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是我们可以用来从数据库上下文或http上下文中获取信息的某种方法。