Net Core 3用户角色,取决于租户

问题描述 投票:0回答:1

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

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

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

因此,该角色不仅链接到用户,还链接到他为其操作的客户。是否可以使用Net Core 3身份管理这种类型的授权?

asp.net-core asp.net-core-identity
1个回答
0
投票

“因此,角色不仅链接到用户,而且还链接到为其操作的客户”

首先,您需要一个存储操作员-角色-客户关系的表。您可以扩展内置的AspNetUserRoles表,也可以创建一个全新的表。由于我们不知道您的应用程序的外观,因此我将创建一个新表来说明如何执行此操作。假设我们有两个运算符:

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

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

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

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

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

  • [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的方式)>

© www.soinside.com 2019 - 2024. All rights reserved.