如何验证 JwtSecurityToken 自定义属性
Posted
技术标签:
【中文标题】如何验证 JwtSecurityToken 自定义属性【英文标题】:How to Validate JwtSecurityToken Custom Property 【发布时间】:2020-04-18 04:26:17 【问题描述】:我正在尝试将自定义属性添加到在 ASP.NET Core Web API (3.1) 中生成的不记名令牌。我目前有一个运行良好的登录过程,它将发出一个用于授权请求的不记名令牌。我可以看到一个问题,如果有人破解用户名并通过,他们将拥有有效的 JWT 并可以访问我的 api。
我正在将此 API 用于移动应用 (flutter),并希望增加额外的安全性。使用颤振/飞镖,我可以访问一个唯一的设备 ID。我希望在不记名令牌中包含设备 ID,并根据请求从发出的 JWT 中提取设备 ID,并从 DEVICE_ID 请求标头值中对其进行验证,以确认它来自最初请求并生成 JWT 的同一设备.
我的第一个问题是我该怎么做?我找到了一篇关于 Payload (token.Payload["custom prop"] = ...) 的帖子 here,但我如何在授权期间提取它?有没有更好的不同方法来实现这一点?
我希望保留验证,这样我就可以简单地继续使用我的 api 控制器方法上方的 [Authorize] 属性。
这是我的启动 ConfigureServices 方法
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
options.TokenValidationParameters = new TokenValidationParameters
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["Jwt:Issuer"],
ValidAudience = Configuration["Jwt:Issuer"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])),
;
);
这里是我生成令牌的地方:
private string GenerateJSONWebToken(UserModel user)
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
;
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Issuer"],
claims,
expires: DateTime.Now.AddMinutes(120),
signingCredentials: credentials);
token.Payload["DEVICE_ID"] = 1001; // Added here just as example of Payload
var encodeToken = new JwtSecurityTokenHandler().WriteToken(token);
return encodeToken;
这里有一些只需要[Authorize]属性自动拒绝错误请求的地方方法:
[Authorize]
[HttpPost("Post")]
public string Post()
var identity = HttpContext.User.Identity as ClaimsIdentity;
IList<Claim> claim = identity.Claims.ToList();
var userName = claim[0].Value;
return "Welcome To: " + userName;
[Authorize]
[HttpGet("GetValue")]
public ActionResult<IEnumerable<string>> Get()
return new string[] "Value1", "Value2", "Value3" ;
我使用 this 在线教程为 API 构建了 JWT 授权。谢谢你的帮助。
我刚刚找到this (Microsoft: TokenValidationParameters.PropertyBag 并试图找到一些示例。在文档中它说“包含自定义键/值对的集合。这允许添加可用于自定义令牌验证场景的参数。”
【问题讨论】:
【参考方案1】:您可以使用这样的负载来使用自定义声明:
var claims = new[]
new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
new Claim(JwtRegisteredClaimNames.Email, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim("device_id", "smaple_id")); // custom property claim
;
现在这里是一种简单的方法,而不是使用中间件创建自定义令牌验证器。
app.UseAuthentication();
app.Use(async (context, next) =>
var deviceId = context.User.Claims.SingleOrDefault(x => x.Type == "device_id");
var validationResult = DoSomeValidation(deviceId)
if (validationResult == false)
context.Response.StatusCode = 401;
await context.Response.WriteAsync("Unauthorized Device");
await next.Invoke();
);
要获得更简洁的代码,请在扩展方法中使用 from middleware。
【讨论】:
【参考方案2】:Claims-Based authorization 是使用自定义声明的便捷方式。在您的 Startup.cs 中,您可以输入以下内容:
services.AddAuthorization(options =>
options.AddPolicy("policy1", policy => policy.RequireClaim("CustomClaimName", "Accepted Value"));
);
然后在您的控制器中,您可以在要保护的方法中添加:
[Authorize(Policy = "policy1")]
【讨论】:
以上是关于如何验证 JwtSecurityToken 自定义属性的主要内容,如果未能解决你的问题,请参考以下文章
无法加载类型“System.IdentityModel.Tokens.JwtSecurityToken”