从 TokenValidatedContext 获取签名
Posted
技术标签:
【中文标题】从 TokenValidatedContext 获取签名【英文标题】:get signature from TokenValidatedContext 【发布时间】: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 + . + 第二个字符串
那应该给我没有签名的令牌。有没有更好的想法来从完整的令牌中删除签名?
我为什么要实现这个目标?
这个问题是基于这个问题
Security token from TokenValidatedContext from the OnTokenValidated event listener is missing last string segment
我正在使用访问和刷新令牌。在验证期间,我必须将请求中的令牌与数据库中的令牌进行比较。数据库中的令牌也包含签名。所以我面临与上面链接相同的问题。
这就是为什么我想到了多种解决方案并将它们写在这里。如果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);
这就是为什么我要为它存储一个额外的到期日期。它应该可以在一段时间后过期。
登录
将用户生成的访问和刷新令牌及其到期时间存储到数据库中。将完整访问令牌或无签名访问令牌存储到数据库(取决于此问题的解决方案)。
命中受保护的端点
检查该用户的访问令牌是否存在于数据库中。
点击刷新端点
检查数据库刷新令牌是否已过期。如果不是,请将其与请求中的刷新令牌进行比较。如果一切正常,从数据库中删除旧的访问和刷新令牌,并将新生成的访问和刷新令牌存储到数据库中。
退出
从数据库中删除该访问及其连接的刷新令牌。
【问题讨论】:
【参考方案1】:我不太明白你为什么要这样做,但如果你只需要原始令牌,你可以使用以下之一:
o.Events = new JwtBearerEvents
OnTokenValidated = (context) =>
var securityToken = (System.IdentityModel.Tokens.Jwt.JwtSecurityToken)context.SecurityToken;
var token = securityToken.RawData; // "ey...."
var tokenHeader = securityToken.RawHeader; // "ey...."
var tokenPayload = securityToken.RawPayload; // "ey...."
var tokenSignatur = securityToken.RawSignature; // "ey...."
var fullBearerHeader = context.Request.Headers["Authorization"]; // "Bearer ey..."
return Task.CompletedTask;
;
你可能想让代码在类型转换等方面更安全一些,但它应该给你令牌。
【讨论】:
【参考方案2】:为什么要操纵令牌?如果只是为了验证令牌,您可以使用下面的代码。
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
options.TokenValidationParameters = new TokenValidationParameters
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
//ValidIssuer = Configuration["Issuer"],
//ValidAudience = Configuration["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Key"]))
;
);
和
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
app.UseAuthentication();
app.UseMvc();
【讨论】:
感谢您的回复。我已经实现了你的解决方案。我更新了我的问题并添加了一个附加部分 您是否打算在每个请求中刷新访问令牌? 否,但由于我将访问和刷新令牌存储到数据库(一个刷新令牌连接到一个访问令牌),我必须将数据库访问令牌与上下文中的令牌进行比较。但是这个上下文返回一个没有签名的令牌...... 我更新了我的问题,我希望这能让事情变得清晰:)以上是关于从 TokenValidatedContext 获取签名的主要内容,如果未能解决你的问题,请参考以下文章
从一个触发器,如何找出谁修改了表X上的数据,同时该用户从一个通用的dbuser登录,但从用户表获得了权利
为啥我们要包装 HttpServletRequest ? api 提供了一个 HttpServletRequestWrapper 但我们从包装请求中获得了啥?