with users recuperar password net mvc forgot contraseƱa aspnet asp and c# asp.net-mvc-5 asp.net-identity-2 reset-password

c# - users - reset password asp.net identity



ContraseƱa de cambio de identidad de ASP.NET (8)

EDITAR: Sé que el OP solicitó una respuesta que realiza la tarea en una transacción, pero creo que el código es útil para las personas.

Todas las respuestas usan PasswordHasher directamente, lo que no es una buena idea, ya que perderá algunas funciones integradas (validación, etc.).

Una alternativa (y supongo que el enfoque recomendado) es crear un token de restablecimiento de contraseña y luego usarlo para cambiar la contraseña. Ejemplo:

var user = await UserManager.FindByIdAsync(id); var token = await UserManager.GeneratePasswordResetTokenAsync(user); var result = await UserManager.ResetPasswordAsync(user, token, "MyN3wP@ssw0rd");

Necesito la capacidad de cambiar la contraseña del usuario por parte del administrador. Entonces, el administrador no debe ingresar una contraseña actual del usuario, debe tener la capacidad de establecer una nueva contraseña. Miro el método ChangePasswordAsync, pero este método requiere ingresar una contraseña anterior. Entonces, este método no es apropiado para esta tarea. Por eso lo he hecho de la siguiente manera:

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

funciona, pero teóricamente podemos recibir un error en el método AddPasswordAsync. Por lo tanto, se eliminará la contraseña anterior pero no se establece la nueva. No es bueno. ¿Alguna forma de hacerlo en "una transacción"? PD. Vi el método ResetPasswordAsync con token de reinicio, parece que es más seguro (porque no puede ser una situación inestable con el usuario) pero en cualquier caso, lo hace por 2 acciones.


Este método funcionó para mi:

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


Esto es solo un refinamiento de la respuesta proporcionada por @Tseng. (Tuve que ajustarlo para que funcione).

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

Nota: esto se aplica específicamente a una configuración modificada que usa int como las claves principales para usuarios y roles. Creo que sería simplemente una cuestión de eliminar los <AppUser, int> tipo <AppUser, int> para que funcione con la configuración predeterminada de Identidad ASP.NET.


Sí, estás en lo correcto. ResetPassword a través del token es un enfoque preferido. En algún momento, creé un contenedor completo sobre .NET Identity y el código se puede encontrar here . Puede ser útil para ti. También puedes encontrar nuget here . También expliqué la biblioteca en un blog here . Este contenedor es fácilmente consumible como nuget y crea todas las configuraciones necesarias durante la instalación.


Si no tiene la contraseña actual del usuario y aún desea cambiar la contraseña. Lo que podría hacer en su lugar, eliminar primero la contraseña del usuario y luego agregar la nueva contraseña. De esta manera, podrá cambiar la contraseña del usuario sin necesidad de la contraseña actual de ese usuario.

await UserManager.RemovePasswordAsync(user); await UserManager.AddPasswordAsync(user, model.Password);


ApplicationUserManager es la clase generada por la plantilla ASP.NET.

Lo que significa que puede editarlo y agregar cualquier funcionalidad que aún no tenga. La clase UserManager tiene una propiedad protegida llamada Store que almacena una referencia a la clase UserStore (o cualquier subclase de la misma, dependiendo de cómo configuró su identidad ASP.NET o si usa implementaciones de almacenamiento de usuario personalizadas, es decir, si usa un motor de base de datos diferente como 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 }); } if(PasswordValidator != null) { var passwordResult = await PasswordValidator.ValidateAsync(password); if(!password.Result.Success) return passwordResult; } var newPasswordHash = this.PasswordHasher.HashPassword(newPassword); await store.SetPasswordHashAsync(userId, newPasswordHash); return Task.FromResult<IdentityResult>(IdentityResult.Success); } }

El UserManager no es más que un contenedor del UserStore subyacente. Consulte la documentación de la interfaz IUserPasswordStore en MSDN sobre los métodos disponibles.

Editar: PasswordHasher también es una propiedad pública de la clase UserManager , consulte la definición de interfaz aquí .

Edición 2: como algunas personas creen ingenuamente , no se puede validar la contraseña de esta manera, la actualicé. La propiedad PasswordValidator también es una propiedad de UserManager y es tan simple como agregar 2 líneas de código para agregar también la validación de contraseña (que no era un requisito de la pregunta original).


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


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

Nota: aquí UserId estoy recuperando del usuario registrado actual.