【问题标题】:Decode custom JSON claim from JwtSecurityTokenHandler从 JwtSecurityTokenHandler 解码自定义 JSON 声明
【发布时间】:2021-11-20 12:45:21
【问题描述】:

我有一个 JWT,我想使用 Microsoft.IdentityModel.Tokens 包中的 System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler 类对其进行解码。我可以毫无问题地解码所有标准声明。

但是,我在 JWT 中有一个自定义声明,如下所示:

{
  "exp": 1632825287,
  ...
  "my_custom_claim": {
    "ctx": "...",
    "act": "a826e63f-1c31-4f01-b432-f1264794e7ac"
  }
}

我使用以下代码:

var jwtTokenHandler = new JwtSecurityTokenHandler();
var decodedJwtToken = jwtTokenHandler.ReadJwtToken(encodedJwtToken);
object customClaim = decodedJwtToken.Payload["my_custom_claim"];
// customClaim is wrapped as object, the underlying type is Microsoft.IdentityModel.Json.Linq.JObject

我的问题是:如何解码/访问“my_custom_claim”中包含的“act”子声明的值? 因为Microsoft.IdentityModel.Json 命名空间中的所有类型都是内部的,所以我没有机会对其进行解码。

【问题讨论】:

  • var act = decodedJwtToken.Payload["my_custom_claim"]["act"]?
  • 这不起作用,因为decodedJwtToken.Payload["my_custom_claim"] 是对象类型。它抛出“错误 CS0021:无法使用 [] 将索引应用于‘object’类型的表达式”。

标签: c# jwt


【解决方案1】:

我发现的唯一方法是另外使用 Newtonsoft.Json 包,这是我原本想避免的。 我想出的最简单的解决方案是:

var jwtTokenHandler = new JwtSecurityTokenHandler();
var decodedJwtToken = jwtTokenHandler.ReadJwtToken(encodedJwtToken);
var customClaim = decodedJwtToken.Claims.Single(claim => claim.Type == "my_custom_claim");
// The following line requires: using Newtonsoft.Json.Linq
var actClaim = JObject.Parse(customClaim.Value)["act"].ToString();

【讨论】:

    【解决方案2】:

    您可以从 JWT 获取所有声明为 Dictionary<string, string>,然后使用 Newtonsoft.Json(或任何其他等效项)将自定义声明 JSON 反序列化为特定类型。

    class CustomClaimType 
    {
        public string Ctx { get; set; }
        public string Act{ get; set; }
        // other props ... 
    }
    
    var encodedToken = "eyJ0eXAiOiJK....";
    var jwtTokenHandler = new JwtSecurityTokenHandler();
    var decodedToken = jwtTokenHandler.ReadJwtToken(encodedToken);
    
    var claims = decodedToken.Claims
        .GroupBy(claim => claim.Type) // handle arrays
        .ToDictionary(
             claim => claim.Key, 
             claim => string.Join(" ", claim.Select(claim => claim.Value)));
    
    var customClaim = JsonConvert.DeserializeObject<CustomClaimType>(
        claims["my_custom_claim"], 
        new JsonSerializerSettings 
        { 
            ContractResolver = new CamelCasePropertyNamesContractResolver() 
        });
    

    【讨论】:

    • 与此同时,我提出了一个类似的解决方案,也使用了Newtonsoft.Json。我想避免这种情况,但似乎没有其他可能性。为了完整起见,我将发布我的答案。无论如何感谢您的建议!
    猜你喜欢
    • 2019-02-26
    • 2013-11-05
    • 2018-09-09
    • 1970-01-01
    • 1970-01-01
    • 2018-11-12
    • 1970-01-01
    • 2017-07-27
    • 2021-09-09
    相关资源
    最近更新 更多