DataProtectorTokenProvider 一次性配置
DataProtectorTokenProvider single use configuration
我正在尝试生成令牌以重置密码并使用 ASP .NET 将其发送到用户电子邮件。
但是,在验证之后,用户可以再次单击相同的 link,它仍然是 returns。我想配置为仅限一次性使用。
这是生成代码的地方
var code = await identityUserManager.GeneratePasswordResetTokenAsync(user.Id); //the code is generated here
这里是验证代码的地方
UserManager.VerifyUserToken(userId, "ResetPassword", code) //still return true after second click in Email
请帮帮我!非常感谢!
有两种方法可以解决这个问题:-
按照方法一,我们用token实现过期时间。在这里,用户仍然可以重复使用该代码,如果 过期时间超过要求。更好的解决办法是放一些RouteGuards
,如方法2所示。这样做,不会允许用户第二次访问重设密码页面,without 生成新代码。因此,用户在这里只能使用一次代码。但是,那一次使用不会过期
所以,为了兼顾这两个好处,我建议同时实现这样用户将只能使用一次代码,并且在过期时间之前也是如此。
方法 1 -(为令牌实施过期时间)
创建一个包含 3 列(TokenCode、IssuedToEmailId、ExpireTime)的数据库来存储相同的内容,以 EmaildId 作为主键,这样一次就不会再向用户颁发一个令牌。在下面提供的 ForgetPassword()
中生成令牌,删除该用户 table 中的任何先前行,并插入新数据 -> 令牌代码、用户的电子邮件 ID 和到期时间,即,假设Datetime.Now.AddMinutes(10);
并且在下面提供的ResetPassword()
中,使用电子邮件ID从table中检索数据,并比较Datetime.Now < ExpireTime
如果为真,则继续,否则显示过期代码错误。
方法二-(实现路由守卫)
我的密码重置代码流程是,在忘记密码页面上,我只要求提供电子邮件地址,然后,让我们点击一个按钮开始令牌生成、电子邮件发送等过程。因此,在成功发送电子邮件后,我执行 return Ok()
,然后在 sessionStorage
中启动会话并导航到重置密码页面。现在,一旦到了这里,我检查同一会话的可用性,如果没有找到,我知道它已被删除,我将用户导航到我想要的任何地方,但如果会话存在,我要求输入代码新密码,确认新密码,然后,假设单击按钮开始密码重置过程,然后在其 return Ok()
上,我删除了该会话。
因此,如果用户尝试通过访问重置密码 url 再次使用相同的令牌,他没有该会话,因此可以导航到我想要的任何位置。
这样我就不需要验证用户token了。
代码 =>
忘记密码:-
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
// If user has to activate his email to confirm his account, the use code listing below
//if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
//{
// return Ok();
//}
if (user == null)
{
return NotFound();
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
await UserManager.SendEmailAsync(user.Id, "Reset Password for AJWebApp", $"Please reset your password by using this => {code}");
return Ok();
}
// If we got this far, something failed, redisplay form
return BadRequest(ModelState);
}
重置密码代码:-
public async Task<IHttpActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return Ok();
}
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
if (result.Succeeded)
{
return Ok();
}
return Ok();
}
我正在尝试生成令牌以重置密码并使用 ASP .NET 将其发送到用户电子邮件。 但是,在验证之后,用户可以再次单击相同的 link,它仍然是 returns。我想配置为仅限一次性使用。 这是生成代码的地方
var code = await identityUserManager.GeneratePasswordResetTokenAsync(user.Id); //the code is generated here
这里是验证代码的地方
UserManager.VerifyUserToken(userId, "ResetPassword", code) //still return true after second click in Email
请帮帮我!非常感谢!
有两种方法可以解决这个问题:-
按照方法一,我们用token实现过期时间。在这里,用户仍然可以重复使用该代码,如果 过期时间超过要求。更好的解决办法是放一些RouteGuards
,如方法2所示。这样做,不会允许用户第二次访问重设密码页面,without 生成新代码。因此,用户在这里只能使用一次代码。但是,那一次使用不会过期
所以,为了兼顾这两个好处,我建议同时实现这样用户将只能使用一次代码,并且在过期时间之前也是如此。
方法 1 -(为令牌实施过期时间)
创建一个包含 3 列(TokenCode、IssuedToEmailId、ExpireTime)的数据库来存储相同的内容,以 EmaildId 作为主键,这样一次就不会再向用户颁发一个令牌。在下面提供的 ForgetPassword()
中生成令牌,删除该用户 table 中的任何先前行,并插入新数据 -> 令牌代码、用户的电子邮件 ID 和到期时间,即,假设Datetime.Now.AddMinutes(10);
并且在下面提供的ResetPassword()
中,使用电子邮件ID从table中检索数据,并比较Datetime.Now < ExpireTime
如果为真,则继续,否则显示过期代码错误。
方法二-(实现路由守卫)
我的密码重置代码流程是,在忘记密码页面上,我只要求提供电子邮件地址,然后,让我们点击一个按钮开始令牌生成、电子邮件发送等过程。因此,在成功发送电子邮件后,我执行 return Ok()
,然后在 sessionStorage
中启动会话并导航到重置密码页面。现在,一旦到了这里,我检查同一会话的可用性,如果没有找到,我知道它已被删除,我将用户导航到我想要的任何地方,但如果会话存在,我要求输入代码新密码,确认新密码,然后,假设单击按钮开始密码重置过程,然后在其 return Ok()
上,我删除了该会话。
因此,如果用户尝试通过访问重置密码 url 再次使用相同的令牌,他没有该会话,因此可以导航到我想要的任何位置。 这样我就不需要验证用户token了。
代码 =>
忘记密码:-
public async Task<IHttpActionResult> ForgotPassword(ForgotPasswordViewModel model)
{
if (ModelState.IsValid)
{
var user = await UserManager.FindByNameAsync(model.Email);
// If user has to activate his email to confirm his account, the use code listing below
//if (user == null || !(await UserManager.IsEmailConfirmedAsync(user.Id)))
//{
// return Ok();
//}
if (user == null)
{
return NotFound();
}
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
// Send an email with this link
string code = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
await UserManager.SendEmailAsync(user.Id, "Reset Password for AJWebApp", $"Please reset your password by using this => {code}");
return Ok();
}
// If we got this far, something failed, redisplay form
return BadRequest(ModelState);
}
重置密码代码:-
public async Task<IHttpActionResult> ResetPassword(ResetPasswordViewModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = await UserManager.FindByNameAsync(model.Email);
if (user == null)
{
// Don't reveal that the user does not exist
return Ok();
}
var result = await UserManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
if (result.Succeeded)
{
return Ok();
}
return Ok();
}