如何基于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
相关产品推荐
相关产品推荐

