单次使用 Jwt Token 在 angular 6 的 asp.net 核心中进行电子邮件验证
Posted
技术标签:
【中文标题】单次使用 Jwt Token 在 angular 6 的 asp.net 核心中进行电子邮件验证【英文标题】:Single time use Jwt Token for email verification in asp.net core with angular 6 【发布时间】:2019-03-15 07:12:41 【问题描述】:我,正在使用 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 小时后到期。但是,当用户从电子邮件网址导航时,它会首次验证电子邮件。这对我有用。
现在,当用户再次导航时,链接应该不起作用。我如何限制用户进行一次电子邮件验证,或者他们是否可以通过任何方式从 asp.net 核心创建一次使用 jwt 令牌。
【问题讨论】:
【参考方案1】:嗯,有可能做到这一点。但不建议这样做。
一个普通的JWT
令牌通常存储在客户端,服务器将在收到JWT
令牌时对其进行验证。在验证 JWT
令牌时,服务器被认为是某种“无状态”。他们只是验证签名、颁发者、受众、生命周期等。
所以如果我们想要一个一次性令牌,我们必须在服务器端维护一个状态以防止客户端replay attack。换句话说,我们将有一个与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
一起存储在数据库中,并通过过滤器、模型绑定甚至手动验证它。
【讨论】:
你能告诉我用 Angular 6 应用程序在 asp.net 核心中创建和验证令牌的最佳方法吗? @SanJaisy 你能告诉我们你想使用 OneTimeOnlyToken 的场景是什么吗? 用户注册到网站。然后他/她会收到一封电子邮件。当他/她浏览链接电子邮件确认需要完成。当他们再次点击该链接时,该链接应过期。 @SanJaisy 如果您只有一个地方可以验证token
,只需将令牌与“HasBeenConsumed”一起存储并通过操作过滤器或手动进行验证。
@SanJaisy 验证“HasBeenConsumed”和令牌的方法与我在答案中发布的完全一样。以上是关于单次使用 Jwt Token 在 angular 6 的 asp.net 核心中进行电子邮件验证的主要内容,如果未能解决你的问题,请参考以下文章
Angular:JWT Token 在 Postman 上运行良好,但在我的应用程序中运行良好
Spring Security Jwt Token在请求表单角度时允许所有Options方法