wake-up-neo.com

Wie implementiere ich das Zurücksetzen des Kennworts mit ASP.NET Identity für ASP.NET MVC 5.0?

Microsoft hat ein neues Mitgliedersystem mit dem Namen ASP.NET Identity (ebenfalls das Standardsystem in ASP.NET MVC 5). Ich habe das Beispielprojekt gefunden, aber hiermit ist kein Passwortreset implementiert.

Beim Thema zum Zurücksetzen des Kennworts wurde gerade dieser Artikel gefunden: Implementieren der Benutzerbestätigung und des Zurücksetzens des Kennworts mit einer ASP.NET-Identität - Schmerz oder Vergnügen , keine Hilfe für mich, da die integrierte Kennwortwiederherstellung nicht verwendet wird.

Als ich mir die Optionen angesehen habe, denke ich, dass wir ein Reset-Token generieren müssen, das ich an den Benutzer senden werde. Der Benutzer kann dann das neue Passwort unter Verwendung des Tokens einstellen und das alte überschreiben.

Ich habe den IdentityManager.Passwords.GenerateResetPasswordToken/IdentityManager.Passwords.GenerateResetPasswordTokenAsync(string tokenId, string userName, validUntilUtc) gefunden, aber ich konnte nicht herausfinden, was der tokenId -Parameter bedeuten könnte.

Wie implementiere ich das Zurücksetzen des Kennworts in ASP.NET mit MVC 5.0?

28
Gábor Plesz

Ich verstehe: Die Token-ID ist eine frei gewählte Identität, die eine Passwortoption identifiziert. Beispielsweise,

1. sieht aus wie der Passwortwiederherstellungsprozess, Schritt 1 (basiert auf: 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 Und wenn der Benutzer das Token und das neue Passwort eingibt:

[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-VorschlagBeispielprojekt auf Github, falls jemand es braucht, kann es getestet werden.

8
Gábor Plesz

Scheint eine Menge Ärger zu sein ... Welchen Vorteil hat das oben Genannte gegenüber:

  1. der Benutzer klickt auf den Link "Konto wiederherstellen"
  2. dadurch wird eine 64-Byte-codierte Zeichenfolge mit einem Datums-/Uhrzeit-Tick-Wert (Pseudo-Hash genannt) in einer E-Mail gesendet
  3. klicken Sie auf den Link zurück in der E-Mail zu einem Controller/einer Aktionsroute, der/die
  4. gleicht die E-Mail und den Quellserver mit dem Pseudo-Hash ab, entschlüsselt den Pseudo-Hash, überprüft die seit dem Senden verstrichene Zeit und
  5. bietet dem Benutzer eine Ansicht zum Festlegen eines neuen Kennworts
  6. mit einem gültigen Kennwort entfernt der Code das alte Benutzerkennwort und weist das neue zu.
  7. Sobald der Vorgang abgeschlossen ist, löschen Sie den Pseudo-Hash.

Mit diesem Flow senden Sie NIEMALS ein Passwort aus Ihrer Domain heraus.

Bitte, irgendjemand, beweisen Sie mir, dass dies weniger sicher ist.

5
Robert Achmann