c# - 使用 JWT 在 Web API 的每个请求中设置声明主体
问题描述
我有 SPA 作为 React 中的前端应用程序和 APP.NET Web API 中的后端应用程序。我有一个对用户进行身份验证的身份管理,因此我们从 React 应用程序直接对身份管理系统进行 API 调用,以传递用户凭据。一旦通过身份验证,我们就会通过调用后端 API 来显示用户的基本详细信息。我有一个具有身份验证过滤器属性的基本控制器,因此我们将设置 httpusercontext 和主体对象。所以首先我检查如果没有设置 httpcontext.currrent.user.name
- 从身份管理返回的请求标头中获取用户名
- 从数据库中按用户名获取用户详细信息并设置声明
- 检查标头是否有 JWT 令牌,如果有,则验证它,如果没有,则将令牌添加到标头
- 设置httpcontext
代码看起来像
if ((HttpContext.Current != null && HttpContext.Current.User != null && HttpContext.Current.User.Identity != null && string.IsNullOrEmpty(HttpContext.Current.User.Identity.Name)))
{
IEnumerable<string> tokenHeaders;
//get the value of username from Idenity Access management
if (request.Headers.TryGetValues("username", out tokenHeaders))
{
userId = tokenHeaders.FirstOrDefault();
if (userId != null)
{
ClientModel clientModel = new ClientModel();
//get all the details to construct claims from database
clientModel = _processor.GetDetailsByUsername(userId);
var claims = new List<Claim>
{
new Claim("FirstName", clientModel.FirstName),
new Claim("LastName", clientModel.LastName),
new Claim(ClaimTypes.Name, clientModel.UserName),
new Claim("ClientId", clientModel.UserId.ToString()),
new Claim(ClaimTypes.Email, clientModel.EmailId)
};
//check if JwtToken exists and if not create access and refresh token
if (!request.Headers.Contains("JwtToken"))
{
jwtTokenViewModel = new JwtTokenViewModel();
jwtTokenViewModel.AccessToken = _tokenService.GenerateAccessToken(claims);
jwtTokenViewModel.RefreshToken = _tokenService.GenerateRefreshToken();
//TODO: persist refresh token
context.ActionContext.Request.Properties.Add("JwtTokenProperty", jwtTokenViewModel);
}
else
{
//validate the token
IEnumerable<string> headerValues = request.Headers.GetValues("JwtToken");
var accessToken = headerValues.FirstOrDefault();
var principal = _tokenService.GetPrincipalFromExpiredToken(accessToken);
if (principal == null)
{
ShowAuthenticationError(context);
}
}
ClaimsIdentity identity = new ClaimsIdentity(claims);
Thread.CurrentPrincipal = new ClaimsPrincipal(new[] { identity });
System.Web.HttpContext.Current.User = new ClaimsPrincipal(new[] { identity });
}
}
}
它有效,但据我了解 httpcontext 对该请求有效,因为 httpcontext.current.user.name 对于每个请求都是空的。这是使用个人帐户而不是 Windows 身份验证。该方法的一个问题是对于我们调用数据库并设置主体对象的每个请求。所以我想知道使用令牌来设置声明是否是一个更好的主意。所以我在考虑过滤器中的以下步骤
如果标记出现在标头中
- 验证令牌并从令牌中获取声明
- 设置声明并设置 httpcontext 用户
如果标头中没有标记
- 从请求头中获取用户名
- 从数据库中获取用户详细信息并设置声明
- 根据声明生成令牌并将其添加到标头
所以代码看起来像
if(!request.Headers.Contains("JwtToken"))
{
IEnumerable<string> tokenHeaders;
//get the value of username from Idenity Access management
if (request.Headers.TryGetValues("username", out tokenHeaders))
{
userId = tokenHeaders.FirstOrDefault();
if (userId != null)
{
ClientModel clientModel = new ClientModel();
//get all the details to construct claims from database
clientModel = _processor.GetDetailsByUsername(userId);
var claims = new List<Claim>
{
new Claim("FirstName", clientModel.FirstName),
new Claim("LastName", clientModel.LastName),
new Claim(ClaimTypes.Name, clientModel.UserName),
new Claim("ClientId", clientModel.UserId.ToString()),
new Claim(ClaimTypes.Email, clientModel.EmailId)
};
//check if JwtToken exists and if not create access and refresh token
if (!request.Headers.Contains("JwtToken"))
{
jwtTokenViewModel = new JwtTokenViewModel();
jwtTokenViewModel.AccessToken = _tokenService.GenerateAccessToken(claims);
jwtTokenViewModel.RefreshToken = _tokenService.GenerateRefreshToken();
//TODO: persist refresh token
context.ActionContext.Request.Properties.Add("JwtTokenProperty", jwtTokenViewModel);
}
}
}
}
else
{
//validate the token
IEnumerable<string> headerValues = request.Headers.GetValues("JwtToken");
var accessToken = headerValues.FirstOrDefault();
var principal = _tokenService.GetPrincipalFromExpiredToken(accessToken);
if (principal == null)
{
ShowAuthenticationError(context);
}
}
ClaimsIdentity identity = new ClaimsIdentity(claims);
Thread.CurrentPrincipal = new ClaimsPrincipal(new[] { identity });
System.Web.HttpContext.Current.User = new ClaimsPrincipal(new[] { identity });
通过上述方法,我们可以避免每个请求都调用数据库。但是我们在令牌中包含了用户 ID(我认为无论如何我都需要它来验证)。请让我知道什么是更好的方法以及为什么以及是否还有其他更好的方法。
解决方案
推荐阅读
- javascript - 如何将动态配置传递给 Gruntfile.js
- java - 如何使用 Selenium TestNG 和 Java 将背景颜色 RGB(255, 255, 255) 与#fff 进行转换和匹配
- python - 尝试循环浏览网页以进行数据抓取时出错
- javascript - 如何在js中使用带有箭头函数的2个条件过滤对象数组?
- react-native - 擦除键Listner反应原生
- java - 当程序尝试从实体流中反序列化对象时出现错误
- vim - 无法更改 .vimrc 中的高亮组设置
- c# - 将隐藏字段添加到复选框列表
- elasticsearch - 嵌套过滤器聚合包括 doc_count 中的空文档
- java - Maven Java Surefire 无法创建测试类