如何从 .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 声明。您实际上在控制器中经过身份验证的用户中看到了哪些声明?在某些情况下,某些声明也会被忽略。
【讨论】:
是的,我知道要重命名声明。我尝试了您提到的选项和设置,但没有成功。 我可以从控制器中IHttpContextAccessor
的Authorization
标头获取令牌吗?在每个控制器中这样做会有什么缺点吗?
您应该从 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 声明角色