Подтвердить что ты не робот

Пароль смены идентификатора ASP.NET

Мне нужно изменить пароль для пользователя по администратора. Таким образом, администратор не должен вводить текущий пароль пользователя, он должен иметь возможность устанавливать новый пароль. Я смотрю на метод ChangePasswordAsync, но для этого метода требуется ввести старый пароль. Таким образом, этот метод не подходит для этой задачи. Поэтому я сделал это следующим образом:

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

он работает, но теоретически мы можем получить ошибку в методе AddPasswordAsync. Таким образом, старый пароль будет удален, но новый не будет установлен. Это не хорошо. Любой способ сделать это в "одной транзакции"? PS. Я видел метод ResetPasswordAsync с токеном reset, кажется, он более безопасен (потому что не может быть нестабильной ситуацией с пользователем), но в любом случае он выполняет 2 действия.

4b9b3361

Ответ 1

ApplicationUserManager - это класс, сгенерированный шаблоном ASP.NET.

Это означает, что вы можете редактировать его и добавлять любые функции, которых у него еще нет. Класс UserManager имеет защищенное свойство с именем Store, в котором хранится ссылка на класс UserStore (или любой его подкласс, в зависимости от того, как вы настроили свою идентификацию ASP.NET или если вы используете пользовательские реализации хранилища пользователей, т.е. если вы использовать другой движок базы данных (например, 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 does not 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);
    }
}

UserManager - не что иное, как обертка для нижележащего UserStore. Ознакомьтесь с документацией по интерфейсу IUserPasswordStore на MSDN о доступных методах.

Изменить: PasswordHasher также является публичным свойством класса UserManager, см. определение интерфейса здесь.

Изменить 2: Поскольку некоторые люди наивно верят, вы не можете выполнить проверку пароля таким образом, я обновил его. Свойство PasswordValidator также является свойством UserManager и его так же просто, как добавить 2 строки кода, чтобы добавить проверку пароля (хотя это не было требованием исходного вопроса).

Ответ 2

Этот метод работал у меня:

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

Ответ 3

EDIT: я знаю, что OP запросил ответ, который выполняет задачу в одной транзакции, но я думаю, что код полезен людям.

Все ответы используют PasswordHasher напрямую, что не является хорошей идеей, так как вы потеряете некоторые испеченные функциональные возможности (валидация и т.д.).

Альтернативой (и я бы предположил, что рекомендуемый подход) заключается в создании пароля reset, а затем использовать его для изменения пароля. Пример:

var user = await UserManager.FindByIdAsync(id);

var token = await UserManager.GeneratePasswordResetTokenAsync(user);

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

Ответ 4

Это просто уточнение ответа, предоставленного @Tseng. (Я должен был настроить его, чтобы заставить его работать).

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

Примечание. Это относится только к модифицированной настройке, которая использует int в качестве основных ключей для пользователей и ролей. Я считаю, что просто нужно было бы удалить args <AppUser, int>, чтобы заставить его работать с установкой ASP.NET по умолчанию.

Ответ 5

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

Примечание: здесь UserId я извлекаю из текущего пользователя.

Ответ 6

Если у вас нет текущего пароля пользователя и вы все еще хотите сменить пароль. Что вы можете сделать вместо этого сначала удалить пароль пользователя, а затем добавить новый пароль. Таким образом, вы сможете изменить пароль пользователя без необходимости ввода текущего пароля этого пользователя.

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

Ответ 7

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

Ответ 8

 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;

    }

Ответ 9

Попробуйте удалить старый пароль и добавить новый пароль.

Пример кода:

  var userId = System.Web.HttpContext.Current.User.Identity.GetUserId();
  if (userId != null)
  {
    UserManager<IdentityUser> userManager =
    new UserManager<IdentityUser>(new UserStore<IdentityUser>());
    userManager.RemovePassword(userId);
    String newPassword = "aaaaaaa";
    userManager.AddPassword(userId, newPassword);
  }

Кредиты:

@Brando

Рекомендации:

UserManager RemovePassword: https://msdn.microsoft.com/en-us/library/dn497511(v=vs.108).aspx

UserManager AddPassword: https://msdn.microsoft.com/en-us/library/dn497465(v=vs.108).aspx

Ответ 10

Да, вы правы. ResetPassword через токен - предпочтительный подход. Когда-то назад я создал полную оболочку поверх .NET Identity и код можно найти здесь. Это может быть полезно для вас. Вы также можете найти nuget здесь. Я также объяснил библиотеку в блоге здесь. Эта оболочка легко расходуется как nuget и создает все необходимые конфигурации во время установки.