如何从 .NET Core 6.0 中的 JWT 安全令牌中读取自定义声明值

Posted

技术标签:

【中文标题】如何从 .NET Core 6.0 中的 JWT 安全令牌中读取自定义声明值【英文标题】:How to read custom claim value from JWT security token in .NET Core 6.0 【发布时间】:2022-01-09 05:12:19 【问题描述】:

我无法从 Bearer JWT 令牌中读取令牌声明。

登录正常,HTTP 请求带有一个有效的 JWT 令牌到后端。 登录返回令牌。 这是我在服务器端的代码:

程序.cs

builder.Services.AddAuthentication(m => 
    //m.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    m.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    m.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(conf => 
        conf.RequireHttpsMetadata = false;
    conf.SaveToken = true;
    conf.TokenValidationParameters = new TokenValidationParameters
   
       ValidateIssuer = true,
       ValidateAudience = true,
       ValidIssuer = Configuration["JWT-Issuer"],
       ValidAudience = Configuration["JWT-Issuer"],
       IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWT-Key"])),
       ClockSkew = TimeSpan.Zero,
;
);

当我取消注释这行 //m.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; 邮递员说未经授权。保持注释状态,授权成功。

令牌在这里生成。

生成令牌方法:

private object GenerateJwtToken(string Id, string email, ApplicationUser appUser, string appUserRole, string FirstName)
        
            List<Claim> claims = null;
            claims = new List<Claim> 
                new Claim(JwtRegisteredClaimNames.Email,email),
                new Claim(JwtRegisteredClaimNames.Jti, appUser.Id),
                new Claim("Role",appUserRole),
                new Claim("UserName",appUser.UserName),
                new Claim("TEMP", FirstName)
                
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT-Key"]));
            var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            var expire = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JWT-Expiry"]));


            var token = new JwtSecurityToken(
                issuer: _configuration["JWT-Issuer"],
                audience: _configuration["JWT-Issuer"],
                claims: claims,
                expires: expire,
                signingCredentials: cred
                );


            return new JwtSecurityTokenHandler().WriteToken(token);

        

当 JWT Bearer 令牌被传递给以 [Authorize] 修饰的 API 调用并使用调试器进行测试时,它表明自定义声明 like TEMP 不存在于 User.Claims 列表中。

从令牌中读取声明

  string Email = User.Claims.SingleOrDefault(x => x.Type.Equals("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress")).Value;
  string FirstName= User.Claims.SingleOrDefault(x => x.Type.Equals("TEMP")).Value;

在这里,可以成功读取电子邮件,但我无法从令牌中读取 FirstName。事实上,User.Claims 没有 FirstName 声明(我的意思是所有自定义声明都离开了注册的 JWT 默认声明类型),它只有默认的令牌参数,即电子邮件地址、ID、角色等。

我该怎么办? 我是否需要为此创建自定义身份验证方案?

【问题讨论】:

您能否发布 JWT 令牌的样本副本? eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImFiY0BnbWFpbC5jb20iLCJqdGkiOiJiZGY1MTExMy01ZTI0LTQxMmUtYTgxYS1hZmZjOTZkYjhiOTIiLCJSb2xlIjoiU3VwZXJBZG1pbiIsIlVzZXJOYW1lIjoiQUJDIiwiVEVNUCI6IlN1cGVyIiwiZXhwIjoxNjM4NjEzNzA1LCJpc3MiOiJTdXBlckF3ZXNvbWVUb2tlblNlcnZlciIsImF1ZCI6IlN1cGVyQXdlc29tZVRva2VuU2VydmVyIn0._XSYh4GqR9uxlxCoF3I5pTMKo04sfsd9qCP51ESJVV4 跨度> 这只是一个示例。 【参考方案1】:

在 AddJwtBearer 内部,令牌处理程序完成了一些重新映射,其中声明被重命名,例如

email -> http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress

可以使用以下方法关闭此映射:

// Or set this flag to false
.AddJwtBearer(opt =>

    ...
    opt.MapInboundClaims = false;
);

或设置:

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
JwtSecurityTokenHandler.DefaultOutboundClaimTypeMap.Clear();

实际映射可见here

但是,我不确定为什么找不到 TEMP 声明。您实际上在控制器中经过身份验证的用户中看到了哪些声明?在某些情况下,某些声明也会被忽略。

【讨论】:

是的,我知道要重命名声明。我尝试了您提到的选项和设置,但没有成功。 我可以从控制器中IHttpContextAccessorAuthorization 标头获取令牌吗?在每个控制器中这样做会有什么缺点吗? 您应该从 ClaimsPrincipal 用户对象中获取用户,这是正确的做法,我认为您不会通过一些自定义 hack 获得任何收益。 用户对象中的 IsAuthenticated 属性是否设置为 true?您确定您从令牌中获得了真正的用户吗?因为您需要确定是否接受令牌并创建经过身份验证的用户作为结果 我尝试了第二种方法从令牌中读取声明,我成功了。通过这一行读取 token 并将其转换为 json。 string[] SplitResult = _httpcontext.HttpContext.Request.Headers["Authorization"].ToString().Split(new string[] " " , StringSplitOptions.RemoveEmptyEntries);

以上是关于如何从 .NET Core 6.0 中的 JWT 安全令牌中读取自定义声明值的主要内容,如果未能解决你的问题,请参考以下文章

如何从.Net Core API 中的身份验证 JWT 令牌中获取身份用户?

如何使用.Net Core cookie中间件ticketdataformat将Jwt令牌从Api保存到c#中的cookie

ASP.NET Core JWT 和声明

如何使用剃刀视图 ASP .Net Core 从 JWT 声明角色

从 ASP.NET Core 中的 API 读取 JWT 令牌

如何使用 ASP.NET Core 中的声明检查 JWT 中的权限?