System的自定义对象JSON序列化实现是否存在问题.IdentityModel.代币.Jwt.净6



我们从迁移而来。Net Core(dotnet Core(3.1至。净6。我们正在使用该系统。IdentityModel。代币。Jwt创建一个有效负载并使用该有效负载生成一个安全令牌。

我们的应用程序尚未从Newtonsoft迁移。Json系统。文本Json,因为目前有很多非标准的属性序列化倾向于前者。自定义声明值包含一个对象,该对象以前已通过遵守Startup.cs配置中指定的关于JSON序列化的camelBase协定解析程序而正确序列化。

我们从系统的版本5.5.0升级而来。IdentityModel。代币。Jwt到版本6.16.0,并且序列化行为不同。

我们使用的是IdentityModel知名声明与自定义声明的混合。自定义声明是唯一一个对象,也是唯一一个以这种方式表现的声明。所有其他声明都是基元类型,并按照指定和预期写入令牌。

这是一个不起作用的代码示例:

var payload = new JwtPayload()
{
{JwtRegisteredClaimNames.Iss, issuer},
{JwtRegisteredClaimNames.Iat, now},
{JwtRegisteredClaimNames.Nbf, now},
{JwtRegisteredClaimNames.Exp, exp},
{JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")},
{"role", user.UserType},
{"customClaim", customClaimObjectInstance }
};
var jwt = new JwtSecurityToken(_jwtHeader, payload);
/* Token below contains a valid base64 encoded JWT Token with
the customClaim property containing pascal values that match
the properties of the C# Poco object and not at all following       
either default convention or even any JsonProperty description 
attributes such as [JsonProperty("name")] that may decorate each 
property of the custom object */
var token = _jwtSecurityTokenHandler.WriteToken(jwt);

我的第一个预感是,这可能与系统默认库的冲突有关。文本Json。我通过将[JsonPropertyName("name")]属性添加到某些属性来进行故障排除,但没有成功。我预料到如果系统。文本Json被告知,在声明对象的序列化过程中,至少会尊重或咨询这些描述属性。

我还尝试使用NewtonsoftJsonConverter序列化该值。序列化函数,并将序列化的值用作声明键值对的值。然而,字符串化的对象引号被转义,并在值中发现了大量转义字符("***"(,这是不希望的。

经过一段时间的在线搜索,并试图找到合适的关键词来搜索谷歌和GitHub,我终于找到了我目前认为的解决方案,而不是长期解决方案。

Github上的这个公开问题提供了线索。根据我的解释,我只是通过在实例化问题中发布的有效负载变量之前指定以下行,强制使用Newtonsoft序列化和反序列化委托:

JsonExtensions.Serializer = JsonConvert.SerializeObject;
JsonExtensions.Deserializer = JsonConvert.DeserializeObject;

这是潜在系统的第一个迹象。文本Json被迫从图书馆深处出来。它也可以是对从Newtonsoft.JsonSystem.Text.Json的迁移进行优先级排序的时间已经到来的指示。

我希望这个变通方法能帮助其他人获得这个短期补丁,而不是像我那样花那么多钱。

如果我发现关于这件事的任何具体想法或线索,我会更新这个答案。

以下代码适用于

/* This was the key to achieving the prior result, however 
temporary it may be. */
JsonExtensions.Serializer = JsonConvert.SerializeObject;
JsonExtensions.Deserializer = JsonConvert.DeserializeObject;

var payload = new JwtPayload()
{
{JwtRegisteredClaimNames.Iss, issuer},
{JwtRegisteredClaimNames.Iat, now},
{JwtRegisteredClaimNames.Nbf, now},
{JwtRegisteredClaimNames.Exp, exp},
{JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString("N")},
{"role", user.UserType},
{ "customClaim", customClaimObjectInstance}
};
var jwt = new JwtSecurityToken(_jwtHeader, payload);
var token = _jwtSecurityTokenHandler.WriteToken(jwt);

我感谢github上的问题,但更重要的是这里提出的解决方案。

创建一个扩展到System.IdentityModel.Tokens.Jwt.JwtPayloadCustomJwtPayload类。生成所有构造函数并重写序列化部分,然后可以根据需要进行序列化/反序列化。

在本例中,我使用System.Text.Json.JsonSerializerCamelCase:进行序列化和反序列化

public class CustomJwtPayload : JwtPayload
{
public CustomJwtPayload()
{
}
public CustomJwtPayload(IEnumerable<Claim> claims) : base(claims)
{
}
public CustomJwtPayload(
string issuer,
string audience,
IEnumerable<Claim> claims,
DateTime? notBefore,
DateTime? expires
) : base(issuer, audience, claims, notBefore, expires)
{
}
public CustomJwtPayload(
string issuer,
string audience,
IEnumerable<Claim> claims,
DateTime? notBefore,
DateTime? expires,
DateTime? issuedAt
) : base(issuer, audience, claims, notBefore, expires, issuedAt)
{
}
public CustomJwtPayload(
string issuer,
string audience,
IEnumerable<Claim> claims,
IDictionary<string, object> claimsCollection,
DateTime? notBefore,
DateTime? expires,
DateTime? issuedAt
) : base(
issuer,
audience,
claims,
claimsCollection,
notBefore,
expires,
issuedAt
)
{
}
public override string SerializeToJson()
{
return JsonSerializer.Serialize(
this as IDictionary<string, object>,
new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
}
public static new JwtPayload Base64UrlDeserialize(string base64Json)
{
return JsonSerializer.Deserialize<JwtPayload>(
Base64UrlEncoder.Decode(base64Json),
new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
}
public static new JwtPayload Deserialize(string jsonString)
{
return JsonSerializer.Deserialize<JwtPayload>(
jsonString,
new JsonSerializerOptions()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
}
}

然后将其与JwtSecurityToken(JwtHeader header,JwtPayload payload)构造函数一起使用:

var header = new JwtHeader(credentials);
var payload = new CustomJwtPayload(
...
);
var securityToken = new JwtSecurityToken(header, payload);
// Add even more items
securityToken.Payload.Add("AnotherItem", 120);
var token = new JwtSecurityTokenHandler().WriteToken(securityToken);

JwtSecurityTokenHandler.WriteToken的深层次调用JwtPayload.SerializeToJson(),因此通过重写自定义类中的方法并使用类,您可以完全控制。

最新更新