基于.NET Identity声明式认证实现[Authorize]及JWT补全DB声明
解决方案
1. 生成JWT时加载数据库中存储的所有用户声明
你当前生成JWT仅添加了Name声明,需要通过_userManager获取用户的所有已存储声明,合并到tokenClaims集合中:
// 获取用户在数据库中存储的所有声明(包括Role、ChannelId等) var userClaims = await _userManager.GetClaimsAsync(userExist); // 初始化tokenClaims,保留原有Name声明后合并用户的其他声明 var tokenClaims = new List<Claim> { new(ClaimTypes.Name, userExist.Id), }; tokenClaims.AddRange(userClaims); // 生成并输出JWT var token = GetToken(tokenClaims); var jwt = new JwtSecurityTokenHandler().WriteToken(token);
这样生成的JWT会包含所有存在数据库里的声明,后续授权校验时context.HttpContext.User就能正确读取到这些Claim。
2. 修正自定义授权属性的使用
你写的[Authorize(ClaimType = "Roles", ClaimValues = UserRoles.User]存在两处问题:
- ClaimType应使用
ClaimTypes.Role(和你存储声明时的类型一致),而非字符串"Roles" - 语法缺失闭合的
)
正确的使用方式如下:
[ClaimsAuthorization(ClaimType = ClaimTypes.Role, ClaimValues = new[] { UserRoles.User })]
你的自定义授权属性逻辑本身是正确的,若要更通用可将变量名hasRequiredRole改为hasRequiredClaim,但不影响现有功能。
3. 验证JWT内容
本地调试时可输出JWT字符串,用JWT解码工具查看Payload内容,确认其中包含role、ChannelId等目标声明,以此验证生成逻辑是否生效。
补充:确保GetToken方法正确传入声明
如果你的GetToken方法负责构建JwtSecurityToken,需确保在配置时传入所有合并后的声明:
private JwtSecurityToken GetToken(List<Claim> claims) { var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Secret"])); return new JwtSecurityToken( issuer: _configuration["JWT:ValidIssuer"], audience: _configuration["JWT:ValidAudience"], expires: DateTime.Now.AddHours(3), claims: claims, // 传入所有合并后的声明集合 signingCredentials: new SigningCredentials(authSigningKey, SecurityAlgorithms.HmacSha256) ); }
完成以上步骤后,你的自定义授权逻辑就能正确校验用户是否具备指定的Claim权限。
内容的提问来源于stack exchange,提问作者Dilakshan AT
相关产品推荐
相关产品推荐

