I need ability to change password for user by admin. So, admin should not enter a current password of user, he should have ability to set a new password. I look at ChangePasswordAsync method, but this method requires to enter old password. So, this method is not appropriate for this task. Therefore I have made it by the following way:
[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);
}
it works, but theoretically we can receive error on AddPasswordAsync method. So, old password will be removed but new is not set. It's not good. Any way to do it in "one transaction"? PS. I seen ResetPasswordAsync method with reset token, seems, it's more safe (because can't be unstable situation with user) but in any case, it does by 2 actions.
EDIT: I know the OP requested an answer which performs the task in one transaction but I think the code is useful to people.
All the answers use the PasswordHasher directly which isn't a good idea as you will lose some baked in functionality (validation etc).
An alternative (and I would assume the recommended approach) is to create a password reset token and then use that to change the password. Example:
var user = await UserManager.FindByIdAsync(id);
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
var result = await UserManager.ResetPasswordAsync(user, token, "MyN3wP@ssw0rd");