【问题标题】:Dynamic authorization of roles asp.net core角色动态授权 asp.net core
【发布时间】:2017-12-01 08:39:21
【问题描述】:

这不是一个重复的问题,或者说其他解决方案中给出的解决方案没有奏效。

假设有一个控制器

[Authorize(Roles=//set dynamically)]
public IActionResult DashBoard(LoginModel model)
{
}

我已经尝试了以下问题的解决方案

  1. Add roles to authorize attribute

  2. dynamically assign controller action permissions to roles

  3. dynamically add roles to authorize attribute for controller(错误:句柄方法 - 找不到合适的方法来覆盖)

  4. can policy based authorization be more dynamic

所有这些解决方案都不起作用,因为接口中覆盖的方法不存在(例如,authorizeAttribute 不包含 AuthorizeCore 的定义),或者在某些情况下 IServiceCollection 服务不包含特定方法

【问题讨论】:

标签: asp.net asp.net-core asp.net-identity authorize-attribute role-based-access-control


【解决方案1】:

你不能那样做。 [Authorize(Roles=//set dynamically)] 必须在编译时知道。出于这个原因,也不鼓励使用角色,正如来自 cmets 的 blowdart 链接帖子中所指出的那样。

相反,您应该使用声明和政策。声明是细粒度的权限,例如“CreateCustomer”或“DeleteCustomer”或“ViewDashboard”。

所以你必须像使用它一样

[Authorize(Policy = "ViewDashboard")]

需要在编译时了解这些策略。

public class ViewDashboardRequirement : AuthorizationHandler<ViewDashboardRequirement>, IAuthorizationRequirement
{
    public override void Handle(AuthorizationContext context, ViewDashboardRequirement requirement)
    {
        if (context.User.HasClaim(c => c.Type == "dashboard:read"))
        {
            context.context.Succeed(requirement);
            return;
        }

        // only call fail if you do not want that other AuthorizationHandler may succeed with 
        // a different requirement
        // context.Fail();
    }
}

有关如何生成通用处理程序(而不是为每个策略编写新处理程序)的示例,请参阅我的回答 here

这将允许您创建可配置的角色。现在您可以创建由声明包组成的角色。每个索赔可能是一个政策。当用户登录时,您将属于某个角色的声明添加到用户声明列表中。

  • 支持:ViewDashboard、ViewCustomers、ViewContacts、ManageCases(支持票证)
  • 经理:ViewDashboard、ManageCustomers(查看、编辑、删除)、ManageContacts(查看、编辑、删除)
  • 管理员:ManageDashboard(查看、编辑)

等等。

从评论更新。

您应该能够利用 ASP.NET Core Identity 的声明和角色声明功能而无需更改一行代码,因此您拥有 IdentityRoleIdentityRoleClaim 类。在运行时,您添加一个新的IdentityRole(即“经理”),然后添加多个IdentityRoleClaim(每个权限/策略一个)

【讨论】:

  • 我面临的问题是在需求类中我需要调用 db.我需要为此添加一个数据上下文。但是这个类创建的任何对象都需要一个 datacontecxt 对象
  • 不,你不需要在那里调用 db。要求应该对用户声明进行操作。登录时,您将所需的声明放入ClaimsPrinicipal。然后,每次用户进行身份验证时,您都可以从HttpContext.User.HasClaim(...)HttpContext.User.FindFirst(...) 中访问声明。那么一个角色只是一堆可以在运行时配置的声明(即添加新角色意味着创建一个角色并向其添加某些声明
  • “声明”比“ViewCustomers”或“ManageCustomers”等特定权限多一点
  • @Lobato:声明在那里查看他们是否有权访问页面/webapi。要筛选数据,您需要数据库上的一些标准,例如“ownedBy”和“groupId”、组织 ID 或将其与父组织进行比较(如果您有类似于 Microsoft Dynamics 管理数据访问的方式)。您如果您根据角色调整视图,则可以有一个带有角色名称或 id 的声明数组,但这假设您在编译时知道角色。这就是为什么使用AuthorizeAttributeRoles 属性不再推荐了。声明更具动态性。
  • @Lobato:好吧。在您的 DashController/actions 上,您有 [Authorize(Policy = "ViewDashboard")] 用于检查用户是否有 dashboard:view 策略。不管他属于哪个组,只要他有声明,他就可以访问那个动作或控制器。在其中,您需要阅读他的 groupis、groupids、userid、他所属的公司或您需要的任何内容(无论是从声明中还是从他的 id 中获取并从您的数据库中获取)并将其应用于数据或数据库查询
【解决方案2】:

如果角色授权,我认为您必须使用 Policy。 事实上,基于策略与基于角色的好处之一就是这一点。

【讨论】:

    【解决方案3】:
    public IActionResult Validate(LoginDetails userobj)
           {
              LoginDetails user = new LoginDetails();
             var checklogin = from s in appDbContext.loginDetails where s.UserName == userobj.UserName && s.Password == userobj.Password select s;
    
                   if (checklogin != null && checklogin.Count() > 0)
                   {
                       if (checklogin.FirstOrDefault().Role == 1)
                       {
                           return RedirectToAction("Home");
                       }
                       else if (checklogin.FirstOrDefault().Role == 2)
                       {
                           var UserId = checklogin.FirstOrDefault().LoginId;
                           HttpContext.Session.SetInt32("UserId", UserId);
                           return RedirectToAction("Index1");
                       } 
               }
    
               return RedirectToAction("Failed");
           }
    

    【讨论】:

    • 请在您的回答中添加口头描述。