动态授权角色 ASP.NET Core

14

这不是一个重复的问题,或者说其他解决方案并没有起作用。

假设有一个控制器:

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

我尝试过以下问题中的解决方案:

  1. 将角色添加到授权属性

  2. 动态分配控制器操作权限给角色

  3. 为控制器动态添加角色以进行授权(错误:处理方法-没有找到适合覆盖的方法)

  4. 基于策略的授权可以更具动态性吗

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


1
这里的答案真的很好...https://dev59.com/CVwZ5IYBdhLWcg3wbv7r#31465227 - KJBTech
我已经尝试过了。找不到AuthorizationContext的定义,至于handle方法,它说没有适合重写的方法。 - Sujit.Warrier
请参考https://github.com/VahidN/DNTIdentity。 - mohamad javad Taherian
3个回答

19

你不能这样做。 [Authorize(Roles=//set dynamically)] 必须在编译时知道。此外,基于角色的操作因该原因被不鼓励使用,如blowdart在评论中所指出。

相反,您应该使用声明和策略。声明是细粒度的权限,例如“创建客户”、“删除客户”或“查看仪表板”。

因此,您需要像这样使用它:

[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();
    }
}

关于如何生成通用处理程序(而不是为每个策略编写新的处理程序),可以参见我的回答这里

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

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

等等。

来自评论的更新:

您应该能够在不改变任何代码的情况下利用ASP.NET Core Identity的声明和角色声明能力,因此您有IdentityRoleIdentityRoleClaim类。运行时,您添加一个新的IdentityRole(即“Manager”),然后添加多个IdentityRoleClaim(每个权限/策略一个)。


1
不,你不需要在那里调用db。要求应该在用户声明上操作。当您登录时,将所需的声明放入ClaimsPrinicipal中。然后每次用户进行身份验证时,您可以从HttpContext.User.HasClaim(...)HttpContext.User.FindFirst(...)中访问声明。然后,角色只是一组声明,可以在运行时配置(即添加新角色意味着创建一个角色并向其添加某些声明)。 - Tseng
“Claim”不仅仅是像“ViewCustomers”或“ManageCustomers”这样的特定权限。 - Tseng
必须在身份验证期间完成,而不是在代码的任意位置,因为身份验证发生在每个请求上。您应该能够利用ASP.NET Core Identity的声明和角色声明功能,而无需更改一行代码,因此您拥有IdentityRoleIdentityRoleClaim类。在运行时,您可以添加一个新的IdentityRole(例如“Manager”),然后为每个权限/策略添加多个IdentityRoleClaim - Tseng
1
@Lobato:声明用于查看是否有访问页面/ WebAPI 的权限。要过滤数据,您需要在数据库中设置一些标准,例如“ownedBy”和“groupId”,organizationid或将其与父组织进行比较(如果您有类似于Microsoft Dynamics管理数据访问的方式)。您可以拥有一个声明数组,其中包含角色的名称或ID,如果您根据角色调整视图,则可以调整视图,但这假定您在编译时知道角色。这就是为什么不再推荐使用AuthorizeAttributeRoles属性。声明更加动态。 - Tseng
1
@Lobato:是的。在您的DashController/actions上,您有[Authorize(Policy = "ViewDashboard")],它会检查用户是否具有dashboard:view策略。无论他属于哪个组,只要他拥有该声明,他就可以访问该操作或控制器。在其中,您需要读取他的组、组ID、用户ID、他所属的公司或任何您需要的信息(从声明中获取或仅获取其ID并从数据库中获取),并将其应用于数据或数据库查询。 - Tseng
显示剩余4条评论

0
我认为在授权方面,您应该使用策略(Policy)而不是角色(Role)。事实上,基于策略的授权与基于角色的授权相比有一个好处。

-7
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");
       }

1
请在您的答案中添加口头描述。 - Aalok

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接