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

如何将Claim序列化为JSON时排除Subject字段?

序列化Claim时排除Subject字段的优雅方案

我在基础Web API中使用System.Security.Claims和JWT令牌,已在program.cs中配置.AddAuthentication().AddJwtBearer()及登录方法,运行正常。现需将名为“Host”的自定义Claim(存储请求来源主机名)序列化为JSON返回给客户端。

使用的JSON序列化工具类如下:

public static class JSonHelpers
{
    public static JsonSerializerSettings NoLoop = new() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
    
    public static string SaveAsJson<T>(this T data, Formatting format = Formatting.Indented, JsonSerializerSettings? settings = null)
    {
        try { return JsonConvert.SerializeObject(data, format, settings); }
        catch (Exception ex) { return ex.Message; }
    }
}

初始控制器方法:

[HttpGet("host")]
[Authorize]
[SwaggerResponse(StatusCodes.Status200OK)]
[SwaggerResponse(StatusCodes.Status401Unauthorized)]
[Produces(MediaTypeNames.Text.Plain)]
public string HostClaim()
{
    return User.Claims.Where(c=>c.Type=="Host").ToList().SaveAsJson(settings: JSonHelpers.NoLoop);
}

直接序列化Claim数组时,返回的JSON会包含Subject字段,导致冗余数据过多。目前通过创建匿名类选择所需字段可解决问题,但写法不够优雅,想知道是否可以直接排除不需要的Subject字段。


可行方案

方案1:自定义ContractResolver全局排除Subject字段

修改JSonHelpers,添加自定义的契约解析器,专门排除Claim类的Subject属性:

public static class JSonHelpers
{
    public static JsonSerializerSettings NoLoop = new() 
    { 
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        ContractResolver = new IgnoreClaimSubjectResolver()
    };
    
    public static string SaveAsJson<T>(this T data, Formatting format = Formatting.Indented, JsonSerializerSettings? settings = null)
    {
        try { return JsonConvert.SerializeObject(data, format, settings ?? NoLoop); }
        catch (Exception ex) { return ex.Message; }
    }
    
    private class IgnoreClaimSubjectResolver : DefaultContractResolver
    {
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);
            // 过滤Claim类的Subject属性
            if (member.DeclaringType == typeof(Claim) && member.Name == nameof(Claim.Subject))
            {
                property.ShouldSerialize = _ => false;
            }
            return property;
        }
    }
}

修改后,原控制器方法无需改动,直接调用SaveAsJson就会自动排除Subject字段:

public string HostClaim()
{
    return User.Claims.Where(c=>c.Type=="Host").ToList().SaveAsJson();
}

方案2:封装扩展方法简化匿名类写法

如果不想修改全局序列化设置,可以把匿名类的字段选择逻辑封装成扩展方法,让控制器代码更简洁:

public static class ClaimExtensions
{
    public static object ToSerializableClaim(this Claim claim)
    {
        return new { claim.Issuer, claim.OriginalIssuer, claim.Properties, claim.Type, claim.Value, claim.ValueType };
    }
}

控制器方法即可简化为:

public string HostClaim()
{
    return User.Claims.Where(c=>c.Type=="Host")
                      .Select(c => c.ToSerializableClaim())
                      .ToList()
                      .SaveAsJson(settings: JSonHelpers.NoLoop);
}

内容的提问来源于stack exchange,提问作者Wim ten Brink

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 13:25:15