重现 System.Text.Json 不兼容 JRaw 的代码
var payload = new JwtPayload();
payload.Add("cnf", JRaw.Parse("{\"x5t#S256\":\"foo\"}"));
var newtonsoftJson = Newtonsoft.Json.JsonConvert.SerializeObject(payload);
// output is {"cnf":{"x5t#S256":"foo"}}
var textJson = JsonSerializer.Serialize(payload);
// output is {"cnf":{"x5t#S256":[]}}
IdenitityServer4 受这个问题影响,在 TokenExtensions.cs#L92 中有下面这行代码
var jsonTokens = jsonClaims.Select(x => new { x.Type, JsonValue = JRaw.Parse(x.Value) }).ToArray();
可能是某个版本的 System.IdentityModel.Tokens.Jwt 开始,json 序列化器改用 System.Text.Json,升级 System.IdentityModel.Tokens.Jwt 后如果使用 cnf 就会遇到这个问题,github 上的相关 issue:
如果不使用 Newtonsoft.Json,全部使用 Sytem.Text.Json,可以用 JsonDocument.Parse 取代 JRaw.Parse
payload.Add("cnf", JsonDocument.Parse("{\"x5t#S256\":\"foo\"}"));
对于 IdenitityServer4 的问题,通过引入 CustomJwtPayload 强制使用 Newtonsoft.Json 对 JwtPayload 进行序列化解决了
在 TokenExtensions.cs#L36 中将 var payload = new JwtPayload
改为 var payload = new CustomJwtPayload
CustomJwtPayload 的实现如下:
internal class CustomJwtPayload : JwtPayload
{
public CustomJwtPayload(string issuer, string audience, IEnumerable<Claim> claims, DateTime? notBefore, DateTime? expires) :
base(issuer, audience, claims, notBefore, expires)
{
}
public override string SerializeToJson()
{
return JsonConvert.SerializeObject(this);
}
}
System.IdentityModel.Tokens.Jwt 的开源代码 src/System.IdentityModel.Tokens.Jwt
– dudu 2年前