DataProtectorTokenProvider一次性使用配置

时间:2018-07-06 16:56:10

标签: .net token forgot-password reset-password

我正在尝试生成令牌以重置密码,并使用ASP .NET将其发送到用户电子邮件。 但是,在验证之后,用户可以再次单击相同的链接,但仍返回true。我只想配置为一次性使用。 这是代码生成的地方

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

请帮助我!非常感谢!

1 个答案:

答案 0 :(得分:0)

有两种方法可以解决此问题:-

通过以下方法1,我们使用令牌实现了到期时间。在这里,如果 到期时间比要求的时间长,用户仍然可以重复使用该代码。更好的解决方案是放置一些RouteGuards,如方法2所示。这样做将不允许,不允许用户第二次访问重置密码页面,不用强大>生成新代码。因此,此处用户将只能使用一次代码。但是,这种使用不会过期

因此,为了同时拥有这两种好处,我建议同时实现。这样一来,用户将只能使用一次代码,并且在到期之前也只能使用代码。

方法1-(令牌的有效过期时间)

创建一个数据库,该数据库具有3列(TokenCode,IssendToEmailId,ExpireTime)来存储该列,并以EmaildId作为主键,这样就不会在生成令牌后一次向用户颁发一个令牌。在下面提供的ForgetPassword()中,删除该用户表中的所有前一行,然后插入新数据->令牌代码,用户的电子邮件ID和有效时间,即Datetime.Now.AddMinutes(10); < / p>

然后在下面提供的ResetPassword()中,使用电子邮件ID从表中检索数据,并比较Datetime.Now < ExpireTime(如果为true),继续操作,否则显示过期的代码错误。

方法2-(实施路由防护)

我用于密码重置的代码流程是,在“忘记密码”页面上,我仅要求提供电子邮件地址,然后,让我们单击按钮以启动令牌生成,电子邮件发送等过程。因此,在成功发送电子邮件之后, return Ok(),然后在sessionStorage中开始会话并导航到“重置密码”页面。现在,一旦到达这里,我将检查同一会话的可用性,如果未找到,则表明它已被删除,并且将用户导航到我想要的任何位置,但是,如果该会话存在,则我要求输入新密码,并确认新密码,然后说一次按钮单击开始密码重置过程,并在其return Ok()上删除该会话。

因此,如果用户尝试通过访问重置密码URL尝试再次使用相同的令牌,则他没有该会话,因此可以导航到我想要的任何位置。 这样,我不需要验证用户令牌。

代码=>

忘记密码:-

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();
    }