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

JwtSecurityToken为何无法在JWT中包含Claim的Properties属性?

问题原因

.NET 里的 Claim.Properties 是框架内部用来存储额外元数据的属性,不属于JWT标准规范中的字段。默认的 JwtSecurityTokenHandler 在把Claim序列化到JWT payload时,只会处理Claim的Type和Value,不会读取Properties里的内容,所以这些属性自然不会出现在生成的JWT中。

解决方案

给你三种可行的解决办法,按需选择:

方案1:把额外属性拆成独立Claim

如果属性不需要和Role强绑定,直接添加新的Claim即可;要是需要关联,就自定义Claim类型来区分归属:

foreach(var appRole in userDetails.ApplicationRoles)
{
    // 添加Role本身的Claim
    claims.Add(new Claim(ClaimTypes.Role, appRole.AppRole.Code));
    // 添加关联的属性,用前缀标识属于当前Role
    claims.Add(new Claim($"Role_{appRole.AppRole.Code}_Scope", "Application"));
    claims.Add(new Claim($"Role_{appRole.AppRole.Code}_Foo", "Bar"));
}

这种方式简单直接,属性数量少的时候用起来方便,解析时通过前缀就能找到对应Role的属性。

方案2:把Role和属性打包成JSON作为Claim值

想把Role和属性作为一个整体存储的话,将它们序列化为JSON字符串作为Claim的Value即可:

using System.Text.Json;

foreach(var appRole in userDetails.ApplicationRoles)
{
    var roleData = new {
        RoleCode = appRole.AppRole.Code,
        Scope = "Application",
        Foo = "Bar"
    };
    var jsonStr = JsonSerializer.Serialize(roleData);
    claims.Add(new Claim("RoleWithMetadata", jsonStr));
}

解析JWT时,再把对应Claim的Value反序列化回来:

var roleClaim = principal.Claims.First(c => c.Type == "RoleWithMetadata");
var roleData = JsonSerializer.Deserialize<YourRoleModel>(roleClaim.Value);

方案3:手动构建JwtPayload(最灵活)

如果需要完全自定义JWT的结构,可以直接操作JwtPayload,把Role和属性组织成嵌套结构:

public string CreateToken(IEnumerable<Claim> originalClaims, DateTime expiresAt)
{
    var secretKey = Encoding.ASCII.GetBytes(Configuration.GetValue<string>("SecurityKey"));
    var issuer = Configuration.GetValue<string>("Issuer");
    var audience = Configuration.GetValue<string>("Audience");

    // 构建基础payload,先排除原有的Role Claim
    var payload = new JwtPayload(
        issuer,
        audience,
        originalClaims.Where(c => c.Type != ClaimTypes.Role),
        DateTime.UtcNow,
        expiresAt
    );

    // 手动添加带属性的Role列表
    var roleList = userDetails.ApplicationRoles.Select(r => new {
        Role = r.AppRole.Code,
        Scope = "Application",
        Foo = "Bar"
    }).ToList();
    payload.Add("roles_with_props", roleList);

    // 生成并返回JWT
    var jwtHeader = new JwtHeader(new SigningCredentials(new SymmetricSecurityKey(secretKey), SecurityAlgorithms.HmacSha256Signature));
    var jwt = new JwtSecurityToken(jwtHeader, payload);
    return new JwtSecurityTokenHandler().WriteToken(jwt);
}

这种方式能完全控制JWT的内容结构,适合需要复杂嵌套数据的场景。

内容的提问来源于stack exchange,提问作者Darryl Cat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 19:23:15