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

如何配置ASP.NET Core授权从自定义数据库架构获取用户角色?

问题

我有SQL Server表Users、Roles和SecurityGroups,每张表都包含整数ID和NVARCHAR类型的Name字段,还有映射表User_SecurityGroup和SecurityGroup_Role。用户可属于多个安全组,一个安全组可映射多个角色。

我已经实现了获取用户角色列表的函数:

public async Task<List<string>> GetUserRoles(string userId)
{
    List<string> userRoles = new List<string>();

    try
    {
        var securityGroupIds = db.User.FirstOrDefault(u => u.Id == userId).SecurityGroupIdList.ToList();
        userRoles = db.SecurityGroupRole.Where(sgr => securityGroupIds.Contains(sgr.SecurityGroupId)).Select(sgr => sgr.RoleId).ToList();
    }
    catch (Exception ex)
    {
        throw ex;
    }

    return userRoles;
}

目前User.Identity.Name已通过Windows身份验证正确填充,但不知道如何配置ASP.NET Core,使得在页面添加[Authorize(Roles = "SystemAdmin")]特性时,能调用我的函数获取用户角色列表并验证是否包含SystemAdmin角色。


解决方案

要让ASP.NET Core的[Authorize]特性对接自定义角色逻辑,需通过Claims转换机制将用户角色注入身份声明,具体步骤如下:

1. 自定义Claims转换类

创建实现IClaimsTransformation的类,在其中调用你的角色获取函数,将角色添加到用户的身份声明中:

public class CustomClaimsTransformer : IClaimsTransformation
{
    private readonly YourDbContext _dbContext;
    private readonly IYourRoleService _roleService; // 假设GetUserRoles封装在此服务中

    public CustomClaimsTransformer(YourDbContext dbContext, IYourRoleService roleService)
    {
        _dbContext = dbContext;
        _roleService = roleService;
    }

    public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
    {
        // 避免重复注入角色声明
        if (principal.HasClaim(c => c.Type == ClaimTypes.Role))
        {
            return principal;
        }

        // 从Windows身份中获取用户名,映射到Users表的用户ID
        var userName = principal.Identity.Name;
        var user = await _dbContext.Users.FirstOrDefaultAsync(u => u.Name == userName);
        if (user == null)
        {
            return principal;
        }

        // 获取用户角色ID,转换为角色名称(Authorize特性验证的是角色名)
        var roleIds = await _roleService.GetUserRoles(user.Id.ToString());
        var roles = await _dbContext.Roles
            .Where(r => roleIds.Contains(r.Id.ToString()))
            .Select(r => r.Name)
            .ToListAsync();

        // 注入角色声明
        var identity = new ClaimsIdentity(principal.Identity);
        foreach (var role in roles)
        {
            identity.AddClaim(new Claim(ClaimTypes.Role, role));
        }

        return new ClaimsPrincipal(identity);
    }
}

2. 注册服务到依赖注入容器

在Program.cs中注册自定义转换类和角色服务:

builder.Services.AddScoped<IClaimsTransformation, CustomClaimsTransformer>();
builder.Services.AddScoped<IYourRoleService, YourRoleService>(); // 注册你的角色服务

3. 修正角色获取函数逻辑

原函数返回的是RoleId,但[Authorize(Roles = "...")]验证的是角色名称,可以直接修改函数返回角色名:

public async Task<List<string>> GetUserRoles(string userId)
{
    try
    {
        var user = await db.Users
            .Include(u => u.User_SecurityGroup)
            .FirstOrDefaultAsync(u => u.Id == userId);
        
        if (user == null)
        {
            return new List<string>();
        }

        var securityGroupIds = user.User_SecurityGroup.Select(usg => usg.SecurityGroupId).ToList();
        var roleIds = db.SecurityGroupRole
            .Where(sgr => securityGroupIds.Contains(sgr.SecurityGroupId))
            .Select(sgr => sgr.RoleId)
            .ToList();
        
        return await db.Roles
            .Where(r => roleIds.Contains(r.Id))
            .Select(r => r.Name)
            .ToListAsync();
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

4. 确认Windows身份验证配置

确保Program.cs中已启用Windows身份验证:

builder.Services.AddAuthentication(IISDefaults.AuthenticationScheme);
builder.Services.AddAuthorization();

额外提示

  • 可添加缓存逻辑,避免每次请求都查询数据库获取角色
  • 确保Users表的Name字段与Windows身份返回的User.Identity.Name格式一致(如DOMAIN\Username)
  • 处理用户不存在的边界情况,避免空引用异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 00:43:11