.NET6中创建值为整数类型的System.Security.Claim的正确方法
嗨,我来帮你搞定这个问题!你现在遇到的核心困扰是:用C#生成JWT时,iat(签发时间)声明被序列化成了带双引号的字符串,而目标API只认整数类型的iat,虽然手动替换字符串能临时解决,但这显然不是最规范的做法对吧?
其实问题出在你用Claim集合构建JwtPayload的方式上——哪怕你给Claim指定了ValueType为"Integer64",JwtPayload在初始化时还是会把所有Claim的Value当作字符串存储,序列化自然就带上引号了。不用这么麻烦手动改字符串,咱们有更标准的处理方式:
正确做法:直接构建JwtPayload对象,指定整数类型的iat
JwtPayload本质上是一个Dictionary<string, object>,可以直接往里面添加不同类型的值,这样序列化时就能保留整数类型了。结合JwtSecurityTokenHandler来生成JWT,全程不用手动拼接字符串,还能避免出错:
using System.IdentityModel.Tokens.Jwt; using System.Security.Claims; using Microsoft.IdentityModel.Tokens; // 1. 构建JWT Payload,直接添加整数类型的iat var payload = new JwtPayload { { JwtRegisteredClaimNames.Iat, DateTimeOffset.Now.ToUnixTimeSeconds() }, // 按需添加其他声明,比如签发者、主体等 { JwtRegisteredClaimNames.Iss, "your-issuer-value" }, { JwtRegisteredClaimNames.Sub, "your-subject-value" }, // 其他自定义声明也可以直接加,比如整数类型的exp(过期时间) { JwtRegisteredClaimNames.Exp, DateTimeOffset.Now.AddHours(1).ToUnixTimeSeconds() } }; // 2. 构建JWT Header,这里用你从Azure Key Vault获取的私钥创建签名凭据 // 假设你已经获取到了私钥对象(比如AsymmetricSecurityKey类型) var signingCredentials = new SigningCredentials(yourAzurePrivateKey, SecurityAlgorithms.RsaSha256); var header = new JwtHeader(signingCredentials); // 3. 生成JWT令牌 var securityToken = new JwtSecurityToken(header, payload); var tokenHandler = new JwtSecurityTokenHandler(); var finalJwtToken = tokenHandler.WriteToken(securityToken);
为什么之前的方法不生效?
你之前给Claim指定ValueType为"Integer64"没起作用,是因为JwtPayload从Claim集合初始化时,只会读取Claim.Value的字符串内容,并不会根据ValueType自动转换数据类型。所以不管你怎么设置ValueType,最终都会被序列化成字符串。
为啥手动替换不是最佳选择?
虽然替换字符串能临时解决问题,但这种方式很脆弱:如果payload里其他字段也有类似的字符串(比如某个自定义声明的值刚好包含"iat\":\""),就会被误替换,导致JWT失效。而且这种“hack”式的写法维护性很差,后续别人看代码也会困惑。
用上面的标准方式生成JWT,既能保证iat是整数类型,符合API的要求,又能遵循JWT的规范,代码也更清晰易维护。
备注:内容来源于stack exchange,提问作者Dorian-B

