在 .NET Core 2 Web Api 中验证 JWT 后获取用户数据的最佳做法是啥?
Posted
技术标签:
【中文标题】在 .NET Core 2 Web Api 中验证 JWT 后获取用户数据的最佳做法是啥?【英文标题】:What is the best practice for fetching User data after validating JWT in .NET Core 2 Web Api?在 .NET Core 2 Web Api 中验证 JWT 后获取用户数据的最佳做法是什么? 【发布时间】:2018-06-04 01:17:13 【问题描述】:我正在从 MVC 转向 SPA + API 方法,以开发我正在制作的新应用程序,并且面临一些我似乎无法找到答案的问题。
我在 .Net Core 2 中有一个 Web API,它使用 Identity 作为其用户存储。我通过发布 JWT 令牌来保护 API,我的 SPA 在向我的控制器发出的每个请求中作为不记名令牌发送这些令牌。发行代码为:
private async Task<object> GenerateJwtTokenAsync(ApplicationUser user)
var roles = await _userManager.GetRolesAsync(user);
var claims = new List<Claim>
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id)
;
claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JwtKey"]));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expires = DateTime.Now.AddDays(Convert.ToDouble(_configuration["JwtExpireDays"]));
var token = new JwtSecurityToken(
_configuration["JwtIssuer"],
_configuration["JwtIssuer"],
claims,
expires: expires,
signingCredentials: creds
);
return new JwtSecurityTokenHandler().WriteToken(token);
我的问题是:获取在控制器中处理请求所需的用户信息的最佳做法是什么?
当我获得 JWT 令牌时,我有用户信息,但是关于用户的扩展信息,例如他们为哪家公司工作,在我的 SQL 数据库中。
// GET: api/Agreements
[HttpGet]
public async Task<IEnumerable<Agreement>> GetAgreementsAsync()
var user = await _userManager.GetUserAsync(HttpContext.User);
return _context.Agreements.Where(x => x.CompanyId == user.CompanyId);
我是否需要再次访问数据库以获取有关每个请求的信息?此信息是否应该放在 JWT 令牌中,在这种情况下,您应该在哪个字段中放置“自定义”信息?
【问题讨论】:
【参考方案1】:最好在授权时保持无状态,这意味着当客户端通过身份验证并获得 JWT 令牌时,服务器可以使用 JWT 令牌即时授权请求。这意味着服务器不会在任何地方寻找 JWT 令牌,而不是在数据库或内存中。因此,您无需在数据库或其他地方查找开销。
要回答您的问题,您还应该知道声明背后的原因:“与给定实体关联的声明集可以被认为是一个键。特定的声明定义了该键的形状;很像物理钥匙用于打开门上的锁。通过这种方式,声明用于获取资源。”来自MSDN
您不需要向 DB 发出另一个请求,但请记住,Claims 最适合用于授权目的,因此主要在 JWT 中添加额外的声明,以便您以后无需访问数据库即可对 API 资源进行授权。您还可以将自定义声明添加到然后将其加密为 JWT 令牌并发送给客户端的令牌。
身份验证后,您可以将 companyId 和/或 userId 存储在声明中,并且您可以命名任何您想要的字符串,因为这就是声明构造函数的实现方式。当请求到达时,您可以从声明中获取 companyId。例如,将其简单命名为“companyId”。
var claims = new List<Claim>
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(ClaimTypes.NameIdentifier, user.Id),
new Claim("companyId", user.companyId.ToString()) // Like this
;
然后为公司 id 声明写 getter
HttpContext.User.FindFirst("companyId").Value
另外请记住,对于复杂的用户数据,您不应该使用这样的声明,因为这些数据会在网络中传递,并且您不需要大量的 JWT 令牌。这也不是一个好的做法,因为您可以使用 HttpContext.Session 来存储数据并在请求到来时获取它。这里不是详细写Session存储的地方。
【讨论】:
以上是关于在 .NET Core 2 Web Api 中验证 JWT 后获取用户数据的最佳做法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在 HTTPS 上使用 Windows 身份验证首次调用 ASP.NET Core 2.0 Web API 在 Chrome 中总是失败
.NET Core Web API / Angular 应用程序中的 Windows 身份验证
.Net Core 2.0 Web API using JWT - 添加身份会破坏 JWT 身份验证
text 使用ASP.NET Core 2 Web API,Angular 5,.NET核心身份和Facebook登录进行JWT身份验证
如何使用 .AddJwtBearer() 在 .NET Core Web API 中验证 AWS Cognito JWT