【问题标题】:Net Core 3 User role depending on tenantNet Core 3 用户角色取决于租户
【发布时间】:2020-02-09 17:27:00
【问题描述】:

我有一个关于在使用 Net Core 3 开发的 REST 服务中管理用户和角色的问题 我正在研究 ASP NET Core 3 中用户和角色管理的工作原理,但我有一个疑问:通常用户与角色相关联。

在控制器方法中,您可以指定可以访问哪些角色的方法。 但是,如果我的用户的角色根据他工作的客户而改变,我该如何管理呢?

让我解释一下:用户可以访问应用程序,然后选择为哪个客户端工作。 根据选择的客户,它可能具有不同的角色:客户 A 的管理员、客户 B 的协作者等。

因此,该角色不仅与用户相关联,还与他所服务的客户相关联。 是否可以使用 Net Core 3 身份管理这种类型的授权?

【问题讨论】:

    标签: asp.net-core asp.net-core-identity


    【解决方案1】:

    “因此,角色不仅与用户相关联,还与他所操作的客户相关联”

    首先,您需要一个存储 Operator-Role-Customer 关系的表。您可以扩展内置的AspNetUserRoles 表,或者创建一个全新的表。由于我们不知道您的应用程序是什么样子,因此我将创建一个新表来说明如何执行此操作。假设我们有两个运算符:

    • op1 既是客户 1 的管理员又是合作者,
    • op2 是客户 2 的合作者:
     operatorId    |    roleId      |    customerId
    ---------------+----------------+-----------------
      op1          | Administrator  |        1
    ---------------+----------------+-----------------
      op1          | Collaborator   |        2
    ---------------+----------------+-----------------
      op2          | Collaborator   |        2
    

    然后我们可以定义一个CheckOperatorRoleForCustomer策略来动态检查操作员-角色-客户关系,而不是直接使用[Authorize(Roles="xxx")]

    services.AddAuthorization(opts =>{
        opts.AddPolicy("CheckAdminForCustomer", pb =>{
            pb.RequireAuthenticatedUser().AddRequirements(new OpRoleForCustomerRequirement("Administrator"));
        });
        opts.AddPolicy("CheckCollaboratorForCustomer", pb =>{
            pb.RequireAuthenticatedUser().AddRequirements(new OpRoleForCustomerRequirement("Collaborator"));
        });
    });
    services.AddHttpContextAccessor();
    services.AddScoped<IAuthorizationHandler, OpRoleForCustomerHandler>();
    

    这里的OpRoleForCustomerHandler 是一个AuthorizationHandler,用于检查当前用户是否具有指定客户所需的角色。

    为方便起见,我在这里定义了两个策略:

    • CheckAdminForCustomer:检查当前用户是否具有指定客户的管理员角色
    • CheckCollaboratorForCustomer:检查当前用户是否具有指定客户的协作者角色

    然后您可以通过以下方式应用该政策:

    [Authorize(Policy="CheckAdminForCustomer")]
    public IActionResult Profile(int CustomerId)
    {
    

    这种模式就是所谓的Policy-Based Authorization,比基于角色的授权更强大。

    最后,这是我实现的OpRoleForCustomerHandler,供大家参考:

    public class OpRoleForCustomerRequirement: IAuthorizationRequirement
    {
        public OpRoleForCustomerRequirement(string RoleId)
        {
            this.RoleId = RoleId;
        }
        public string RoleId{get;set;}
    }
    public class OpRoleForCustomerHandler: AuthorizationHandler<OpRoleForCustomerRequirement> 
    {
        private readonly AppIdentityDbContext _dbContext;
        private readonly UserManager<IdentityUser> _userManager;
        private readonly IHttpContextAccessor _httpAccessor;
    
        public OpRoleForCustomerHandler(AppIdentityDbContext dbContext, UserManager<IdentityUser> userManager, IHttpContextAccessor accessor) 
        {
            this._dbContext = dbContext;
            this._userManager = userManager;
            this._httpAccessor = accessor;
        }
    
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, OpRoleForCustomerRequirement requirement)
        {
            if(context.User==null) { /* ...log... */ context.Fail(); return; }
            var user = await this._userManager.GetUserAsync(context.User);
    
            var httpContext = this._httpAccessor.HttpContext;
            // get customId from HttpContext/RouteData/....
            // for example ....
            var customIdStr = httpContext.Request.Query["customerId"].FirstOrDefault(); 
    
            if (!string.IsNullOrEmpty(customIdStr) ) { 
                var matches = this._dbContext.OpRoleForCustomers
                    .Any(opc => 
                        opc.OperatorId == user.Id 
                        && opc.RoleId == requirement.RoleId 
                        && opc.CustmerId == customIdStr
                    );
                if(matches){ context.Succeed(requirement) ; return; }
            }
            context.Fail();
        }
    }
    

    (您可能想要自定义从 HttpContext/RouteData/... 获取 customId 的方式)

    【讨论】:

      猜你喜欢
      • 2020-04-03
      • 2020-01-17
      • 2018-11-13
      • 1970-01-01
      • 1970-01-01
      • 2018-09-13
      • 2012-12-04
      • 2016-07-30
      • 1970-01-01
      相关资源
      最近更新 更多