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

如何基于JwtBearerDefaults.AuthenticationScheme配置多角色权限控制?

问题分析与解决方案

你当前的问题核心有两点:一是未配置User认证方案(代码仅注册了Admin的JWT验证规则),导致[Authorize(AuthenticationSchemes = "User")]无法生效;二是仅做了认证校验,未添加角色授权限制,所以只要Token有效就能访问所有接口。以下是具体解决步骤:


步骤1:生成Token时添加角色Claim

在生成JWT Token的代码中,必须为不同用户添加ClaimTypes.Role声明,这是角色授权的核心依据:

// 生成Admin角色的Token示例
var adminClaims = new List<Claim>
{
    new Claim(ClaimTypes.Name, "admin_username"),
    new Claim(ClaimTypes.Role, "Admin") // 指定用户角色
};

var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.UTF8.GetBytes(builder.Configuration["Token:SecurityKey"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = new ClaimsIdentity(adminClaims),
    Expires = DateTime.UtcNow.AddHours(1),
    Issuer = builder.Configuration["Token:Issuer"],
    Audience = builder.Configuration["Token:Audience"],
    SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var adminToken = tokenHandler.CreateToken(tokenDescriptor);

// 生成User角色的Token只需将Role Claim改为"User"即可

步骤2:调整JWT认证配置

根据你的需求选择以下两种配置方式:

方式1:单一认证方案(Admin和User共用一套Token参数)

如果Admin和User的Token使用相同的Issuer、Audience和密钥,只需保留一套认证配置,并确保正确识别角色声明:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = true,
            ValidateIssuer = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,

            ValidAudience = builder.Configuration["Token:Audience"],
            ValidIssuer = builder.Configuration["Token:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Token:SecurityKey"])),
            LifetimeValidator = (notBefore, expires, securityToken, validationParameters) => expires != null ? expires > DateTime.UtcNow : false,

            NameClaimType = ClaimTypes.Name,
            RoleClaimType = ClaimTypes.Role // 显式指定角色声明类型(默认值也是此)
        };
    });

方式2:双认证方案(Admin和User使用不同Token参数)

如果需要为Admin和User配置不同的密钥、Issuer等参数,需添加两套JWT验证规则:

builder.Services.AddAuthentication()
    .AddJwtBearer("Admin", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = true,
            ValidateIssuer = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,

            ValidAudience = builder.Configuration["Token:AdminAudience"],
            ValidIssuer = builder.Configuration["Token:AdminIssuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Token:AdminSecurityKey"])),
            LifetimeValidator = (notBefore, expires, securityToken, validationParameters) => expires != null ? expires > DateTime.UtcNow : false,

            NameClaimType = ClaimTypes.Name,
            RoleClaimType = ClaimTypes.Role
        };
    })
    .AddJwtBearer("User", options =>
    {
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateAudience = true,
            ValidateIssuer = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,

            ValidAudience = builder.Configuration["Token:UserAudience"],
            ValidIssuer = builder.Configuration["Token:UserIssuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Token:UserSecurityKey"])),
            LifetimeValidator = (notBefore, expires, securityToken, validationParameters) => expires != null ? expires > DateTime.UtcNow : false,

            NameClaimType = ClaimTypes.Name,
            RoleClaimType = ClaimTypes.Role
        };
    });

步骤3:修改接口授权属性

根据认证配置方式,调整接口的[Authorize]属性,添加角色限制:

对应方式1(单一认证方案)

// 仅允许Admin角色访问
[Authorize(Roles = "Admin")]
[HttpGet]
public IActionResult AllCar()
{
    return Ok(_carRepository.GetAll());
}

// 仅允许User角色访问
[Authorize(Roles = "User")]
[HttpGet("ForUser")]
public IActionResult ForUser()
{
    return Ok(_carRepository.GetAll());
}

对应方式2(双认证方案)

// 仅允许使用Admin认证方案且拥有Admin角色的用户访问
[Authorize(AuthenticationSchemes = "Admin", Roles = "Admin")]
[HttpGet]
public IActionResult AllCar()
{
    return Ok(_carRepository.GetAll());
}

// 仅允许使用User认证方案且拥有User角色的用户访问
[Authorize(AuthenticationSchemes = "User", Roles = "User")]
[HttpGet("ForUser")]
public IActionResult ForUser()
{
    return Ok(_carRepository.GetAll());
}

验证效果

  • 使用Admin角色Token访问AllCar接口返回200,访问ForUser接口返回403(禁止访问);
  • 使用User角色Token访问ForUser接口返回200,访问AllCar接口返回403。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 17:56:13