C# 如何使用 ASP.NET Identity for ASP.NET MVC 5.0 实现密码重置?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19002864/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 13:52:01  来源:igfitidea点击:

How do I implement password reset with ASP.NET Identity for ASP.NET MVC 5.0?

c#.netasp.net-mvcidentitypassword-recovery

提问by Gábor Plesz

Microsoft is coming up with a new Membership system called ASP.NET Identity(also the default in ASP.NET MVC 5). I found the sample project, but this is not implemented a password reset.

Microsoft 正在推出一个名为 ASP.NET Identity(也是 ASP.NET MVC 5 中的默认设置)的新会员系统。我找到了示例项目,但这并没有实现密码重置。

On password reset topic just found this Article: Implementing User Confirmation and Password Reset with One ASP.NET Identity – Pain or Pleasure, not help for me, because do not use the built-in password recovery.

关于密码重置主题,刚刚发现这篇文章:使用一个 ASP.NET 身份实现用户确认和密码重置 – 痛苦或快乐,对我没有帮助,因为不要使用内置的密码恢复。

As I was looking at the options, as I think we need to generate a reset token, which I will send to the user. The user can set then the new password using the token, overwriting the old one.

当我查看选项时,我认为我们需要生成一个重置令牌,我会将其发送给用户。用户可以使用令牌设置新密码,覆盖旧密码。

I found the IdentityManager.Passwords.GenerateResetPasswordToken/ IdentityManager.Passwords.GenerateResetPasswordTokenAsync(string tokenId, string userName, validUntilUtc), but I could not figure out what it might mean the tokenIdparameter.

我找到了IdentityManager.Passwords.GenerateResetPasswordToken/ IdentityManager.Passwords.GenerateResetPasswordTokenAsync(string tokenId, string userName, validUntilUtc),但我无法弄清楚它可能意味着什么tokenId参数。

How do I implement the Password Reset in ASP.NET with MVC 5.0?

如何使用 MVC 5.0 在 ASP.NET 中实现密码重置?

采纳答案by Gábor Plesz

I get it: The tokenid is a freely chosen identity, which identifies a password option. For example,

我明白了:tokenid 是一个自由选择的身份,它标识一个密码选项。例如,

1. looks like the password recovery process, step 1(it is based on: https://stackoverflow.com/a/698879/208922)

1.看起来像密码恢复过程,第1步(它基于:https: //stackoverflow.com/a/698879/208922

[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
//[RecaptchaControlMvc.CaptchaValidator]
public virtual async Task<ActionResult> ResetPassword(
                                              ResetPasswordViewModel rpvm)
{
    string message = null;
    //the token is valid for one day
    var until = DateTime.Now.AddDays(1);
    //We find the user, as the token can not generate the e-mail address, 
    //but the name should be.
    var db = new Context();
    var user = db.Users.SingleOrDefault(x=>x.Email == rpvm.Email);

    var token = new StringBuilder();

    //Prepare a 10-character random text
    using (RNGCryptoServiceProvider 
                        rngCsp = new RNGCryptoServiceProvider())
    {
        var data = new byte[4];
        for (int i = 0; i < 10; i++)
        {
            //filled with an array of random numbers
            rngCsp.GetBytes(data);
            //this is converted into a character from A to Z
            var randomchar = Convert.ToChar(
                                      //produce a random number 
                                      //between 0 and 25
                                      BitConverter.ToUInt32(data, 0) % 26 
                                      //Convert.ToInt32('A')==65
                                      + 65
                             );
            token.Append(randomchar);
        }
    }
    //This will be the password change identifier 
    //that the user will be sent out
    var tokenid = token.ToString();

    if (null!=user)
    {
        //Generating a token
        var result = await IdentityManager
                                .Passwords
                                .GenerateResetPasswordTokenAsync(
                                              tokenid, 
                                              user.UserName, 
                                              until
                           );

        if (result.Success)
        {
            //send the email
            ...
        }
    }
    message = 
        "We have sent a password reset request if the email is verified.";
    return RedirectToAction(
                   MVC.Account.ResetPasswordWithToken(
                               token: string.Empty, 
                               message: message
                   )
           );
}

2 And then when the user enters the token and the new password:

2 然后当用户输入令牌和新密码时:

[HttpPost]
[ValidateAntiForgeryToken]
[AllowAnonymous]
//[RecaptchaControlMvc.CaptchaValidator]
public virtual async Task<ActionResult> ResetPasswordWithToken(
                                            ResetPasswordWithTokenViewModel 
                                                        rpwtvm
                                        )
{
    if (ModelState.IsValid)
    {
        string message = null;
        //reset the password
        var result = await IdentityManager.Passwords.ResetPasswordAsync(
                                                   rpwtvm.Token, 
                                                   rpwtvm.Password
                           );
        if (result.Success)
        { 
            message = "the password has been reset.";
            return RedirectToAction(
                        MVC.Account.ResetPasswordCompleted(message: message)
                   );
        }
        else
        {
            AddErrors(result);
        }
    }
    return View(MVC.Account.ResetPasswordWithToken(rpwtvm));
}

Skeleton proposalto sample projecton github, if anyone needs it may be tested.The E-mail sending not yet written, possibly with the addition soon.

在 github上的示例项目的骨架建议,如果有人需要可以测试它。电子邮件发送尚未写,可能很快就会添加。

回答by Robert Achmann

Seems like a lot of trouble... What advantage does the above give over:

好像很麻烦…… 上面给出的优势是什么:

  1. the user clicking a 'Recover Account' link
  2. this sends an 64 byte encoded string of a datetime ticks value (call it psuedo-hash) in an email
  3. click the link back in the email to a controller/action route that
  4. matches email and it's source server to psuedo-hash, decrypts the psuedo-hash, validates the time since sent and
  5. offers a View for the user to set a new password
  6. with a valid password, the code removes the old user password and assigns the new.
  7. Once complete, successful or not, delete the psuedo-hash.
  1. 用户点击“恢复帐户”链接
  2. 这会在电子邮件中发送日期时间刻度值的 64 字节编码字符串(称为伪哈希)
  3. 单击电子邮件中的链接返回到控制器/操作路由
  4. 将电子邮件及其源服务器与伪散列匹配,解密伪散列,验证自发送以来的时间和
  5. 为用户提供一个视图来设置新密码
  6. 如果密码有效,代码将删除旧用户密码并分配新密码。
  7. 完成后,成功与否,删除伪哈希。

With this flow, at no time do you EVER send a password out of your domain.

使用此流程,您永远不会从域中发送密码。

Please, anyone, prove to me how this is any less secure.

请任何人向我证明这是多么不安全。