You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于当前客户的.NET Identity差异化权限实现方案咨询

基于.NET Identity实现多客户差异化权限方案分析

你的方案完全可行,这是.NET Identity扩展多客户权限控制的典型落地方式,以下是具体的实现细节和优化建议:

1. 自定义权限表设计

你的[UserCustomerPermissions]表结构(UserId, PermissionValue, CustomerId)完全合理,建议补充:

  • 联合主键:用UserId+CustomerId+PermissionValue作为联合主键,避免重复权限记录
  • 外键约束:关联AspNetUsers表(UserId)和你的客户表(CustomerId),保证数据合法性
  • 可选字段:添加CreatedTime、UpdatedTime用于审计追踪

2. 自定义AuthorizationHandler实现

这是核心逻辑,步骤如下:

  • 定义权限需求类:
    public class CustomerPermissionRequirement : IAuthorizationRequirement
    {
        public string PermissionValue { get; }
    
        public CustomerPermissionRequirement(string permissionValue)
        {
            PermissionValue = permissionValue;
        }
    }
    
  • 实现授权处理器:
    public class CustomerPermissionHandler : AuthorizationHandler<CustomerPermissionRequirement>
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly YourDbContext _dbContext;
    
        public CustomerPermissionHandler(IHttpContextAccessor httpContextAccessor, YourDbContext dbContext)
        {
            _httpContextAccessor = httpContextAccessor;
            _dbContext = dbContext;
        }
    
        protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomerPermissionRequirement requirement)
        {
            var httpContext = _httpContextAccessor.HttpContext;
            if (httpContext == null)
            {
                context.Fail();
                return;
            }
    
            // 获取当前活跃客户ID,优先从Session取,其次QueryString
            var customerId = httpContext.Session.GetString("ActiveCustomerId") 
                            ?? httpContext.Request.Query["CustomerId"].FirstOrDefault();
            
            if (string.IsNullOrEmpty(customerId) || !Guid.TryParse(customerId, out var customerGuid))
            {
                context.Fail();
                return;
            }
    
            // 校验用户是否有权访问该客户(防止恶意篡改)
            var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
            var userHasCustomerAccess = await _dbContext.UserCustomers
                .AnyAsync(uc => uc.UserId == userId && uc.CustomerId == customerGuid);
            if (!userHasCustomerAccess)
            {
                context.Fail();
                return;
            }
    
            // 校验用户在该客户下的目标权限
            var hasPermission = await _dbContext.UserCustomerPermissions
                .AnyAsync(u => u.UserId == userId
                            && u.CustomerId == customerGuid
                            && u.PermissionValue == requirement.PermissionValue);
    
            if (hasPermission)
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }
        }
    }
    

3. 注册授权策略与处理器

在Program.cs中配置授权服务:

builder.Services.AddAuthorization(options =>
{
    // 注册单个权限策略
    options.AddPolicy("Permissions.Products.View", policy =>
        policy.Requirements.Add(new CustomerPermissionRequirement("Permissions.Products.View")));
    
    // 批量注册权限策略(权限较多时使用)
    var permissions = new List<string> { "Permissions.Products.View", "Permissions.Products.Create" };
    foreach (var perm in permissions)
    {
        options.AddPolicy(perm, policy =>
            policy.Requirements.Add(new CustomerPermissionRequirement(perm)));
    }
});

// 注册自定义授权处理器与HttpContextAccessor
builder.Services.AddScoped<IAuthorizationHandler, CustomerPermissionHandler>();
builder.Services.AddHttpContextAccessor();

4. 客户切换功能实现

用户通过下拉框选择客户后,后端验证权限并更新Session:

[HttpPost("switch-customer")]
public async Task<IActionResult> SwitchCustomer(Guid customerId)
{
    var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
    var hasAccess = await _dbContext.UserCustomers
        .AnyAsync(uc => uc.UserId == userId && uc.CustomerId == customerId);
    
    if (!hasAccess)
    {
        return Forbid();
    }
    
    HttpContext.Session.SetString("ActiveCustomerId", customerId.ToString());
    return Ok();
}

5. 优化建议

  • 权限缓存:将用户的所有客户权限缓存到内存或Redis中,在登录/切换客户时加载,避免每次授权都查询数据库
  • Claims扩展:切换客户后,可将当前客户的权限添加到用户Claims集合(需更新身份凭证),授权时直接读取Claims减少数据库交互
  • 全局授权过滤器:若大部分接口都需要客户权限校验,注册全局过滤器避免重复添加[Authorize]特性
  • 权限枚举:将PermissionValue定义为枚举类型,避免硬编码字符串,降低出错概率

内容的提问来源于stack exchange,提问作者Gmorken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 23:01:27