【发布时间】:2020-11-19 20:47:52
【问题描述】:
我正在为我的 .NET Core 项目使用 Microsoft.AspNetCore.Authentication.JwtBearer 和 System.IdentityModel.Tokens.Jwt 包。
在配置服务时,我正在向OnTokenValidated 事件添加逻辑。
services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(jwtBearerOptions =>
{
// ... set TokenValidationParameters ...
jwtBearerOptions.Events = new JwtBearerEvents()
{
OnTokenValidated = (tokenValidatedContext) =>
{
JwtSecurityTokenHandler jwtSecurityTokenHandler = new JwtSecurityTokenHandler();
string tokenWithoutSignature = jwtSecurityTokenHandler.WriteToken(tokenValidatedContext.SecurityToken);
// ... full token from request? ...
}
};
});
因为我知道上下文只返回没有签名的令牌,所以我想知道我该怎么做
- 要么获取带有签名的完整令牌
- 或另外将签名添加到
tokenWithoutSignature字符串中
如果这不可能:
我正在以这种方式生成新令牌
public string GenerateAccessToken(IDictionary<string, object> payload)
{
SymmetricSecurityKey symmetricSecurityKey = new SymmetricSecurityKey(Convert.FromBase64String("secret from config"));
SecurityTokenDescriptor tokenDescriptor = new SecurityTokenDescriptor
{
Claims = payload,
Expires = DateTime.Now, // value from config
SigningCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256Signature)
};
JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
SecurityToken securityToken = tokenHandler.CreateToken(tokenDescriptor);
string token = tokenHandler.WriteToken(securityToken);
return token;
}
也许我可以检索
- 没有签名的令牌字符串
- 只有签名
在这个方法内?
如果没有任何效果:
因为我知道不记名令牌总是包含三个部分,例如
header.payload.signature
我可以将字符串段拆分为一个数组,从数组中取出第一个和第二个元素并创建一个新的字符串
firstString + . + 第二个字符串
那应该给我没有签名的令牌。有没有更好的想法来从完整的令牌中删除签名?
我为什么要实现这个目标?
这个问题是基于这个问题
我正在使用访问和刷新令牌。在验证期间,我必须将请求中的令牌与数据库中的令牌进行比较。数据库中的令牌也包含签名。所以我面临与上面链接相同的问题。
这就是为什么我想到了多种解决方案并将它们写在这里。如果TokenValidatedContext 无法将签名返回给我,似乎我必须将 JWT 存储到数据库中而不需要签名。而且对于这种情况,我需要将签名与生成的 JWT 分开。
没有使用刷新令牌我只将用户的最长会话生命周期存储到数据库中。流程就是基于这个想法
Only store the time of the JWT with the highest lifetime to the database instead of the whole JWT
与 使用刷新令牌我想出了以下流程。 既然您知道 OnTokenValidated 处理验证逻辑,以下逻辑是额外的。我有一个数据库表
用户名 |访问令牌 |刷新令牌 | refresh_token_expires_at
主键是用户名+access_token的组合键。刷新令牌只是像这样生成的一些随机字符串
public string GenerateRefreshToken()
{
var randomNumber = new byte[32];
using (var rng = RandomNumberGenerator.Create())
{
rng.GetBytes(randomNumber);
return Convert.ToBase64String(randomNumber);
}
}
这就是为什么我要为它存储一个额外的到期日期。它应该可以在一段时间后过期。
-
登录
将用户生成的访问和刷新令牌及其到期时间存储到数据库中。将完整访问令牌或无签名访问令牌存储到数据库(取决于此问题的解决方案)。
-
命中受保护的端点
检查该用户的访问令牌是否存在于数据库中。
-
点击刷新端点
检查数据库刷新令牌是否已过期。如果不是,请将其与请求中的刷新令牌进行比较。如果一切正常,从数据库中删除旧的访问和刷新令牌,并将新生成的访问和刷新令牌存储到数据库中。
-
退出
从数据库中删除该访问及其连接的刷新令牌。
【问题讨论】: