我对使用Net Core 3开发的REST服务中的管理用户和角色有疑问。我正在研究用户和角色管理在ASP NET Core 3中的工作方式,但是我有一个疑问:通常,用户与角色相关联。
然后在控制器方法中,您可以指定方法可访问的角色。但是,如果我的用户角色根据他所工作的客户而改变,该如何管理?
让我解释一下:用户可以访问应用程序,然后选择要使用的客户端。根据所选的客户,它可能具有不同的角色:客户A的管理员,客户B的协作者,等等。
因此,该角色不仅链接到用户,还链接到他为其操作的客户。是否可以使用Net Core 3身份管理这种类型的授权?
“因此,角色不仅链接到用户,而且还链接到为其操作的客户”:
首先,您需要一个存储操作员-角色-客户关系的表。您可以扩展内置的AspNetUserRoles
表,也可以创建一个全新的表。由于我们不知道您的应用程序的外观,因此我将创建一个新表来说明如何执行此操作。假设我们有两个运算符:
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>();
这里OpRoleForCustomerHandler
是AuthorizationHandler,用于检查当前用户是否具有指定客户的所需角色。
为了方便起见,我在此处定义了两个策略:
然后您可以通过:]应用该策略
[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的方式)>