[英]Single time use Jwt Token for email verification in asp.net core with angular 6
我,正在使用 jwt 令牌进行一次电子邮件验证。
这是生成jwt令牌的c#代码
public string OneTimeTokenGenerationForVerification(string userName, int expireTime, string secretToken)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secretToken);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, userName)
}),
Expires = DateTime.UtcNow.AddHours(expireTime),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
在角边。 我正在验证令牌是否过期或未使用以下代码。
public jwtTokenValidation(token : string) : boolean {
let jwtHelper: JwtHelperService = new JwtHelperService();
if (token != null) {
// Check whether the token is expired and return true or false
return !jwtHelper.isTokenExpired(token);
}
return false;
}
如果令牌过期,上述方法将返回 false。 因为,我将过期时间设置为 2。因此,令牌在 2 小时后过期。 但是,当用户从电子邮件 url 导航时,它会第一次验证电子邮件。 这对我有用。
现在,当用户再次导航时,链接应该不起作用。 我如何才能限制用户进行一次电子邮件验证,或者他们是否可以通过任何方式从 asp.net 核心创建一次使用 jwt 令牌。
嗯,这是可能的。 但不建议这样做。
普通的JWT
令牌通常存储在客户端,服务器将在收到JWT
令牌时对其进行验证。 在验证JWT
令牌时,服务器被认为是“无状态”的。 他们只是验证签名、发行者、受众、生命周期等。
所以如果我们想要一次性令牌,我们必须在服务器端维护一个状态以防止客户端的重放攻击。 换句话说,我们将有一个与JWT
令牌关联的状态,因此我们可以触发一个委托来确定在接收或验证JWT
令牌时令牌是否已被消耗。 例如,我们可以使用OnMessageReceived
来做到这一点:
services.AddAuthentication()
.AddJwtBearer(options =>{
// options.TokenValidationParameters= ...
options.Events = new JwtBearerEvents() {
OnMessageReceived= async (context) => {
var tokenService = context.HttpContext.RequestServices.GetRequiredService<IOneTimeOnlyJwtTokenService>();
if (context.Request.Headers.ContainsKey("Authorization") ){
var header = context.Request.Headers["Authorization"].FirstOrDefault();
if (header.StartsWith("Bearer",StringComparison.OrdinalIgnoreCase)){
var token = header.Substring("Bearer".Length).Trim();
context.Token = token;
}
}
if (context.Token == null) {
return;
}
if (await tokenService.HasBeenConsumed(context.Token))
{
context.Fail("not a valid token");
}
else {
await tokenService.InvalidateToken(context.Token);
}
}
};
});
IOneTimeOnlyJwtTokenService
是一个虚拟服务,有助于处理令牌生成和令牌无效:
public interface IOneTimeOnlyJwtTokenService
{
Task<string> BuildToken(string name, int? expires);
Task<bool> HasBeenConsumed(string token);
Task InvalidateToken(string token);
}
这是一个实现:
public class JwtTokenService : IOneTimeOnlyJwtTokenService
{
private readonly IConfiguration _config;
public JwtTokenService(IConfiguration config )
{
_config = config;
}
/// <summary>
/// Builds the token used for authentication
/// </summary>
/// <param name="email"></param>
/// <returns></returns>
public async Task<string> BuildToken(string userName,int? expireTime)
{
var claims = new[] {
new Claim(ClaimTypes.Name, userName),
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
var sign= new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var expiredAt = expireTime != null ?
DateTime.UtcNow.AddHours((int)expireTime) :
DateTime.Now.AddHours(int.Parse(_config["Jwt:ExpireTime"]));
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims) ,
Expires = expiredAt,
Issuer = _config["Jwt:Issuer"],
Audience = _config["Jwt:Audience"],
SigningCredentials = sign,
};
var tokenHandler = new JwtSecurityTokenHandler();
var token= tokenHandler.CreateToken(tokenDescriptor);
var tokenString=tokenHandler.WriteToken(token);
await this.RegisterToken(tokenString);
return tokenString;
}
private async Task RegisterToken(string token)
{
// register token
}
public async Task<bool> HasBeenConsumed(string token)
{
// check the state of token
}
public async Task InvalidateToken(string token)
{
// persist the invalid state of token
}
}
好的,可以肯定它有效。 但是如果在这种情况下,每次我们收到消息时都会调用委托。 OnTokenValidated
事件也有类似的问题。
最后,虽然可以这样做,但我建议您应该简单地将带有expiredAt
和invalid
的令牌存储在数据库中,并通过过滤器、模型绑定或什至手动对其进行验证。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.