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

如何确保ClaimsPrincipal正确反序列化?解决序列化属性丢失问题

解决ClaimsPrincipal/ClaimsIdentity序列化后反序列化属性丢失的问题

我之前也踩过这个坑,本质原因是:ClaimsPrincipal和ClaimsIdentity属于.NET安全体系的特殊类型,它们的核心数据(比如Claims集合)并不是常规的可读写公共属性,而是通过内部逻辑维护的。Json.NET默认的序列化机制只能识别普通公共属性,直接序列化会丢失关键数据,反序列化自然就得到空对象了。

下面是具体的解决办法——通过自定义Json转换器来处理这两个类型的序列化与反序列化:

第一步:实现ClaimsIdentity的自定义转换器

这个转换器负责处理ClaimsIdentity的序列化逻辑,把它的核心数据(声明集合、Claim类型配置等)转换成可被Json.NET识别的结构,反序列化时再重新构建对象:

public class ClaimsIdentityConverter : JsonConverter<ClaimsIdentity>
{
    public override ClaimsIdentity ReadJson(JsonReader reader, Type objectType, ClaimsIdentity existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        var claims = jsonObject["Claims"].ToObject<List<Claim>>(serializer);
        var identity = new ClaimsIdentity(claims);
        
        // 还原额外属性(按需添加)
        identity.NameClaimType = jsonObject["NameClaimType"]?.ToString() ?? ClaimsIdentity.DefaultNameClaimType;
        identity.RoleClaimType = jsonObject["RoleClaimType"]?.ToString() ?? ClaimsIdentity.DefaultRoleClaimType;
        identity.IsAuthenticated = jsonObject["IsAuthenticated"]?.Value<bool>() ?? false;
        
        return identity;
    }

    public override void WriteJson(JsonWriter writer, ClaimsIdentity value, JsonSerializer serializer)
    {
        var jsonObject = new JObject
        {
            ["Claims"] = JArray.FromObject(value.Claims, serializer),
            ["NameClaimType"] = value.NameClaimType,
            ["RoleClaimType"] = value.RoleClaimType,
            ["IsAuthenticated"] = value.IsAuthenticated
        };
        jsonObject.WriteTo(writer);
    }
}

第二步:实现ClaimsPrincipal的自定义转换器

ClaimsPrincipal本质是多个ClaimsIdentity的集合,所以转换器的逻辑就是处理身份集合的序列化与还原:

public class ClaimsPrincipalConverter : JsonConverter<ClaimsPrincipal>
{
    public override ClaimsPrincipal ReadJson(JsonReader reader, Type objectType, ClaimsPrincipal existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        var jsonObject = JObject.Load(reader);
        var identities = jsonObject["Identities"].ToObject<List<ClaimsIdentity>>(serializer);
        return new ClaimsPrincipal(identities);
    }

    public override void WriteJson(JsonWriter writer, ClaimsPrincipal value, JsonSerializer serializer)
    {
        var jsonObject = new JObject
        {
            ["Identities"] = JArray.FromObject(value.Identities, serializer)
        };
        jsonObject.WriteTo(writer);
    }
}

第三步:使用自定义转换器完成序列化与反序列化

修改你的原有代码,把两个转换器加入到JsonSerializerSettings中,让Json.NET用自定义逻辑处理这两个类型:

var identity = new ClaimsIdentity(new List<Claim>() { new Claim("Role", "Admin") });
var principal = new ClaimsPrincipal(identity);

var settings = new JsonSerializerSettings
{
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
    Converters = new List<JsonConverter>
    {
        new ClaimsIdentityConverter(),
        new ClaimsPrincipalConverter()
    }
};

// 序列化
string serialized = JsonConvert.SerializeObject(principal, settings);

// 反序列化
ClaimsPrincipal deserialized = JsonConvert.DeserializeObject<ClaimsPrincipal>(serialized, settings);

// 现在可以正常访问属性了
var roleClaim = deserialized.Claims.FirstOrDefault(c => c.Type == "Role");
Console.WriteLine(roleClaim?.Value); // 输出:Admin

补充说明

  • 如果需要还原ClaimsIdentity的更多属性(比如Name、AuthenticationType),可以在转换器的ReadJson和WriteJson方法中添加对应的字段处理;
  • 这个方案支持所有类型的Claim,不止局限于Role声明。

内容的提问来源于stack exchange,提问作者Cristian E.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:18:47