【问题标题】:Asp net Core Identity token authentication expirationAsp net Core Identity 令牌认证过期
【发布时间】:2020-12-10 06:42:13
【问题描述】:
我使用asp net core Identity。这就是我想要做的,我不知道如何做到这一点,所以需要一些专家的帮助。当新用户在我的应用程序中注册时,密码重置链接将发送到此人的电子邮件,现在当链接中的链接令牌已过期并且用户单击该链接时,我需要显示一条消息,因为令牌已过期。当用户单击电子邮件中的链接时,如何确定令牌是否已过期。任何人都可以提出实现这种情况的方法吗?
【问题讨论】:
标签:
c#
asp.net-core
.net-core
【解决方案1】:
ASP.NET Core 有一个内置的声明系统来存储有关用户的信息。
为此,
-
添加一个帮助方法将过期日期时间存储在Register.cshtml.cs:
private async Task AddTokenExpirationInfo(IdentityUser user, int span=1*24*60)
{
var expiresAt = DateTime.Now.Add(TimeSpan.FromMinutes(span));
var tokenExpiredAtClaim = new Claim("ActivtationTokenExpiredAt", expiresAt.ToUniversalTime().Ticks.ToString());
await _userManager.AddClaimAsync(user, tokenExpiredAtClaim);
}
-
在ConfirmEmail.cshtml.cs 中添加一个辅助方法来检查令牌是否已过期:
private async Task<bool> TokenExpiredValidate(IdentityUser user) {
var claims = (await _userManager.GetClaimsAsync(user))
.Where(c => c.Type == "ActivtationTokenExpiredAt");
var expiredAt = claims.FirstOrDefault()?.Value;
bool expired = true; // default value
if (expiredAt != null)
{
var expires = Convert.ToInt64(expiredAt);
var now = DateTime.Now.Ticks;
expired= now <= expires? false : true;
}
else {
expired = false;
}
// clear claims
await _userManager.RemoveClaimsAsync(user, claims);
return expired;
}
-
有注册请求时调用AddTokenExpirationInfo:
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
returnUrl = returnUrl ?? Url.Content("~/");
if (ModelState.IsValid)
{
var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
var result = await _userManager.CreateAsync(user, Input.Password);
if (result.Succeeded)
{
_logger.LogInformation("User created a new account with password.");
var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Page(
"/Account/ConfirmEmail",
pageHandler: null,
values: new { userId = user.Id, code = code },
protocol: Request.Scheme);
await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
$"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");
///////////////// invoke here ////////////////////
AddTokenExpirationInfo(user);
await _signInManager.SignInAsync(user, isPersistent: false);
return LocalRedirect(returnUrl);
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
// If we got this far, something failed, redisplay form
return Page();
}
-
在您的ConfirmEmail.cshtml.cs 中调用TokenExpiredValidate:
public async Task<IActionResult> OnGetAsync(string userId, string code)
{
if (userId == null || code == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userId}'.");
}
var result = await _userManager.ConfirmEmailAsync(user, code);
if (!result.Succeeded)
{
throw new InvalidOperationException($"Error confirming email for user with ID '{userId}':");
}
if (await TokenExpiredValidate(user))
throw new InvalidOperationException($"Token has alread expired '{userId}':");
return Page();
}
当用户注册时,AspNetUserClaims表中会有一条记录:
当用户确认成功后,该记录将被删除。提醒一下,更稳健的方法是使用后台服务清除过期记录。