2015-03-27 21 views
28

Ich brauche die Fähigkeit, das Passwort für den Benutzer von admin ändern. Also, Admin sollte kein aktuelles Passwort des Benutzers eingeben, er sollte die Möglichkeit haben, ein neues Passwort zu setzen. Ich schaue auf ChangePasswordAsync-Methode, aber diese Methode erfordert, altes Passwort einzugeben. Daher ist diese Methode für diese Aufgabe nicht geeignet. Deshalb habe ich es durch die folgende Art und Weise hergestellt:ASP.NET Identität Passwort ändern

[HttpPost] 
    public async Task<ActionResult> ChangePassword(ViewModels.Admin.ChangePasswordViewModel model) 
    { 
     var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>(); 
     var result = await userManager.RemovePasswordAsync(model.UserId); 
     if (result.Succeeded) 
     { 
      result = await userManager.AddPasswordAsync(model.UserId, model.Password); 
      if (result.Succeeded) 
      { 
       return RedirectToAction("UserList"); 
      } 
      else 
      { 
       ModelState.AddModelError("", result.Errors.FirstOrDefault()); 
      } 
     } 
     else 
     { 
      ModelState.AddModelError("", result.Errors.FirstOrDefault()); 
     } 
     return View(model); 
    } 

es funktioniert, aber theoretisch können wir Fehler auf AddPasswordAsync Methode erhalten. Das alte Passwort wird also entfernt, aber das neue Passwort wird nicht gesetzt. Es ist nicht gut. Irgendeine Möglichkeit, es in "einer Transaktion" zu tun? PS. Ich sah ResetPasswordAsync-Methode mit Reset-Token, scheint, es ist sicherer (weil nicht instabil Situation mit Benutzer sein kann), aber in jedem Fall, es durch 2 Aktionen.

+0

Der Kern dieser Frage ist es in einer Transaktion zu tun. Wären Sie zufrieden, es in zwei Transaktionen zu tun und weiter zu versuchen, bis der zweite erfolgreich ist? Wenn nicht, müssen Sie möglicherweise Ihre eigene Implementierung schreiben, um ein Passwort zu ändern. –

Antwort

20

ApplicationUserManager ist die Klasse, die von der ASP.NET-Vorlage generiert wird.

Das bedeutet, Sie können es bearbeiten und jede Funktionalität hinzufügen, die es noch nicht hat. Die UserManager-Klasse verfügt über eine geschützte Eigenschaft mit dem Namen Store, die einen Verweis auf die Klasse UserStore (oder eine Unterklasse davon) speichert, abhängig davon, wie Sie Ihre ASP.NET-Identität konfiguriert haben oder ob Sie benutzerdefinierte Benutzerspeicherimplementierungen verwenden, dh ob Sie eine andere Datenbank-Engine verwenden wie MySQL).

public class AplicationUserManager : UserManager<....> 
{ 
    public async Task<IdentityResult> ChangePasswordAsync(TKey userId, string newPassword) 
    { 
     var store = this.Store as IUserPasswordStore; 
     if(store==null) 
     { 
      var errors = new string[] 
      { 
       "Current UserStore doesn't implement IUserPasswordStore" 
      }; 

      return Task.FromResult<IdentityResult>(new IdentityResult(errors) { Succeeded = false }); 
     } 

     var newPasswordHash = this.PasswordHasher.HashPassword(newPassword); 

     await store.SetPasswordHashAsync(userId, newPasswordHash); 
     return Task.FromResult<IdentityResult>(IdentityResult.Success); 
    } 
} 

Die UserManager ist nichts anderes als ein Wrapper auf die darunter liegenden UserStore. Überprüfen Sie die IUserPasswordStore Schnittstellendokumentation unter MSDN nach verfügbaren Methoden.

Edit: Die PasswordHasher ist auch ein öffentliches Eigentum der UserManager-Klasse finden Sie interface definition here.

+0

Dies ist ein interessanter Ansatz. Ich frage mich, was wir implementieren könnten, so dass das Passwort in einer Transaktion geändert wird, obwohl der Administrator das ursprüngliche Passwort nicht kennt. –

+1

Dieser Ansatz ist eine Transaktion. Sie brauchen kein altes Passwort dafür, da das neu implementierte keine Funktion des alten verwendet und 'SetPasswordHashAsync' direkt von der' UserStore'-Implementierung aufruft, falls welche vorhanden ist. Alles, was Sie wissen müssen, ist die 'userId' und' newPassword' (die Sie zufällig generieren können) – Tseng

30

Diese Methode ist für mich gearbeitet:

public async Task<IHttpActionResult> changePassword(UsercredentialsModel usermodel) 
{ 
    ApplicationUser user = await AppUserManager.FindByIdAsync(usermodel.Id); 
    if (user == null) 
    { 
    return NotFound(); 
    } 
    user.PasswordHash = AppUserManager.PasswordHasher.HashPassword(usermodel.Password); 
    var result = await AppUserManager.UpdateAsync(user); 
    if (!result.Succeeded) 
    { 
    //throw exception...... 
    } 
    return Ok(); 
} 
+5

Während dieser Code gut funktionieren kann, sollte eine gute Antwort auch erklären, wie es funktioniert und warum es eine gute Lösung ist. – Blackwood

+2

default change passwort methoden in der UserManager-klasse versuchen sie zuerst das validieren des passworts und führen sie sicherheitsprüfungen durch, aber ich habe den passwortwert direkt wie ein normales feld aktualisiert, das keine spezielle einschränkung hat. –

+0

Was ist UsercredentialsModel? –

3

Diese auf die Antwort von @Tseng vorgesehen nur eine Verfeinerung ist. (Ich musste zwicken, damit es funktioniert).

public class AppUserManager : UserManager<AppUser, int> 
{ 
    . 
    // standard methods... 
    . 

    public async Task<IdentityResult> ChangePasswordAsync(AppUser user, string newPassword) 
    { 
     if (user == null) 
      throw new ArgumentNullException(nameof(user)); 

     var store = this.Store as IUserPasswordStore<AppUser, int>; 
     if (store == null) 
     { 
      var errors = new string[] { "Current UserStore doesn't implement IUserPasswordStore" }; 
      return IdentityResult.Failed(errors); 
     } 

     var newPasswordHash = this.PasswordHasher.HashPassword(newPassword); 
     await store.SetPasswordHashAsync(user, newPasswordHash); 
     await store.UpdateAsync(user); 
     return IdentityResult.Success; 
    } 
} 

Hinweis: Diese speziell auf eine modifizierte Einrichtung gilt, die int als die Primärschlüssel für Benutzer und Rollen verwendet. Ich glaube, dass es einfach eine Sache sein würde, die <AppUser, int> Art Args zu entfernen, um es mit der Standardinstallation von ASP.NET Identity arbeiten zu lassen.

0
public async Task<ActionResult> ChangePassword(ResetPasswordViewModel CP) 
{ 
    ApplicationDbContext context = new ApplicationDbContext(); 
    UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(context); 
    UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(store); 
    var user = await UserManager.FindAsync(User.Identity.Name, CP.CurrentPassword); 

    if (!UserManager.CheckPassword(user, CP.CurrentPassword)) 
    { 
      ViewBag.notification = "Incorrect password."; 
      return View("~/Views/User/settings.cshtml"); 
    } 
    else 
    { 
      if (CP.Password != CP.ConfirmPassword) 
      { 
       ViewBag.notification = "try again"; 
       return View("~/Views/User/settings.cshtml"); 
      } 
      else 
      { 
       String hashedNewPassword = UserManager.PasswordHasher.HashPassword(CP.Password); 
       await store.SetPasswordHashAsync(user, hashedNewPassword); 
       await store.UpdateAsync(user); 
       ViewBag.notification = "successful"; 
       return View("~/Views/User/settings.cshtml"); 
      } 
     } 
} 
-2

Ja, Sie haben Recht. ResetPassword through Token ist ein bevorzugter Ansatz. Irgendwann zurück, ich habe einen kompletten Wrapper über .NET-Identität erstellt und Code kann gefunden werden. Es könnte für dich hilfreich sein. Sie können auch Nuget here finden. Ich habe die Bibliothek auch in einem Blog here erklärt. Dieser Wrapper kann leicht als nugget konsumiert werden und erstellt während der Installation alle erforderlichen Konfigurationen.

+0

Antworten lieber mit Inhalt in ihnen als externe Links. Wenn diese Verbindungen jemals aus irgendeinem Grund sterben würden, wäre diese Antwort völlig nutzlos. Darüber hinaus beantworten Sie eine zwei Jahre alte Frage mit einer akzeptierten Antwort zwei Jahre später, ohne einen zusätzlichen Wert zu liefern. – shortstuffsushi

11

EDIT: Ich weiß, das OP eine Antwort angefordert, die die Aufgabe in einer Transaktion ausführt, aber ich denke, dass der Code für Menschen nützlich ist.

Alle Antworten verwenden den PasswordHasher direkt, was keine gute Idee ist, da Sie einige eingebrannte Funktionen (Validierung usw.) verlieren werden.

Eine Alternative (und ich würde den empfohlenen Ansatz annehmen) besteht darin, ein Token zum Zurücksetzen des Kennworts zu erstellen und dann das Kennwort zu ändern.Beispiel:

var user = await UserManager.FindByIdAsync(id); 

var token = await UserManager.GeneratePasswordResetTokenAsync(user); 

var result = await UserManager.ResetPasswordAsync(user, token, "[email protected]"); 
+0

Dies scheint der richtige Weg zu sein und eröffnet viele neue Möglichkeiten. Vielen Dank! –

0
public async Task<IActionResult> ChangePassword(ChangePwdViewModel usermodel) 
     {   
      var userId = User.FindFirstValue(ClaimTypes.NameIdentifier); 
      var user = await _userManager.FindByIdAsync(userId);    
      var result = await _userManager.ChangePasswordAsync(user, usermodel.oldPassword, usermodel.newPassword); 
      if (!result.Succeeded) 
      { 
       //throw exception...... 
      } 
      return Ok(); 
     } 

public class ChangePwdViewModel 
    { 
     [DataType(DataType.Password), Required(ErrorMessage ="Old Password Required")] 
     public string oldPassword { get; set; } 

     [DataType(DataType.Password), Required(ErrorMessage ="New Password Required")] 
     public string newPassword { get; set; } 
    } 

Hinweis: hier UserId i von Current bin Abrufen angemeldet Benutzer.

0
public async Task<List<string>> AsyncModifyPassword(LoginDTO entity) 
    { 
     List<string> errors = new List<string>(); 
     ApplicationUser user = await _userManager.FindByEmailAsync(entity.Email); 
     if (user == null) 
     { 
      errors.Add("User Not Found"); //todo, hablar sobre el tema de lanzar las excepciones 
      return errors; 
     } 

     //user.PasswordHash = _userManager.PasswordHasher.HashPassword(user, entity.Password); 
     IdentityResult result = await _userManager.ChangePasswordAsync(user, entity.Password , entity.NewPassword); 

     if (!result.Succeeded) 
      errors = result.Errors.ToList().Select(error => error.Description).ToList(); 

     return errors; 

    } 
+0

Im Allgemeinen sind die Antworten viel hilfreicher, wenn sie eine Erklärung enthalten, was der Code tun soll, und warum das das Problem löst, ohne andere einzuführen. –