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

使用Microsoft.IdentityModel.Tokens创建解析JWT令牌异常求助

问题描述

需要创建包含自定义Claims的JWT令牌,之后验证该令牌并获取ClaimsPrincipal对象。使用的库:

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;

生成令牌的代码如下:

var handler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(AuthSettings.PrivateKey);
var credentials = new SigningCredentials(
    new SymmetricSecurityKey(key),
    SecurityAlgorithms.HmacSha256Signature);

var claims = new List<Claim>
{
    new(JwtRegisteredClaimNames.Sub, user.Username),
    new(JwtRegisteredClaimNames.Jti, user.ID.ToString()),
    new(JwtRegisteredClaimNames.NameId, user.ID.ToString()), 
    new(ClaimTypes.NameIdentifier, user.ID.ToString()), 
    new(ClaimTypes.Role, user.UserPermitionLevel.ToString()),

};
var identity = new GenericIdentity(user.Username);
var claimsidentity = new ClaimsIdentity(identity, claims);
DateTime.UtcNow.AddMinutes(AuthSettings.ExpiryMinutes).ToString())
var tokenDescriptor = new SecurityTokenDescriptor
{
    Subject = claimsidentity, 
    Expires = DateTime.UtcNow.AddMinutes(AuthSettings.ExpiryMinutes),
    SigningCredentials = credentials,
};

var token = handler.CreateToken(tokenDescriptor);
var tk = handler.WriteToken(token);

var res1 = handler.ReadJwtToken(tk);
var res2 = handler.ReadToken(tk);

return handler.WriteToken(token);

生成的令牌Payload包含完整的Claims信息,但调用handler.ReadToken(tk)或handler.ReadJwtToken(tk)读取时,Payload及Claims仅显示4个元素,请求排查解决。


问题排查与解决

1. 先修复语法错误

代码中有一行无意义且语法错误的代码,直接删除:

// 此行无效,删除
DateTime.UtcNow.AddMinutes(AuthSettings.ExpiryMinutes).ToString())

2. ClaimsIdentity构造参数错误(核心问题)

你创建ClaimsIdentity时传参逻辑错误:

// 错误:第二个参数是认证类型字符串,不是Claims集合
var claimsidentity = new ClaimsIdentity(identity, claims);

ClaimsIdentity(IIdentity identity, string authenticationType)的第二个参数是认证类型标识,不是Claims列表。这会导致你定义的5个Claims没有被正确关联到ClaimsIdentity中,后续生成令牌时可能出现Claims缺失或重复映射的问题。

修正后的ClaimsIdentity创建方式:

// 直接传入Claims集合与认证类型,无需额外创建GenericIdentity
var claimsIdentity = new ClaimsIdentity(claims, "HmacSha256Auth");

3. 读取时Claims数量减少的原因

你看到的4个Claims是因为:
JwtRegisteredClaimNames.NameId和ClaimTypes.NameIdentifier本质是同一个Claim的不同命名(前者是JWT标准字段名,后者是.NET内置Claim类型名),在解析时会被自动合并为一个条目。加上sub、jti、role,正好是4个,和你观察到的数量一致。

如果要查看原始未合并的Payload内容,可以直接解析JWT的Base64部分:

var payloadBase64 = tk.Split('.')[1];
// 修复Base64 URL编码的字符替换
var payloadBytes = Convert.FromBase64String(payloadBase64.Replace('-', '+').Replace('_', '/'));
var rawPayload = Encoding.UTF8.GetString(payloadBytes);
// rawPayload会显示完整的原始Claims

4. 正确验证令牌并获取ClaimsPrincipal

要获取包含完整Claims的ClaimsPrincipal,需要使用ValidateToken方法(而非仅读取令牌),这也是生产环境中验证JWT的标准方式:

var tokenString = "生成的JWT令牌";
var handler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(AuthSettings.PrivateKey);

var validationParams = new TokenValidationParameters
{
    ValidateIssuerSigningKey = true,
    IssuerSigningKey = new SymmetricSecurityKey(key),
    ValidateIssuer = false, // 根据业务需求开启/关闭
    ValidateAudience = false, // 根据业务需求开启/关闭
    ClockSkew = TimeSpan.Zero // 关闭时钟偏差容忍
};

// 验证令牌并获取ClaimsPrincipal
var claimsPrincipal = handler.ValidateToken(tokenString, validationParams, out _);

// 获取所有Claims
var allClaims = claimsPrincipal.Claims.ToList();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 13:14:54