管理者がユーザーのパスワードを変更できる必要があります。そのため、管理者はユーザーの現在のパスワードを入力しないでください。新しいパスワードを設定する必要があります。 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メソッドでエラーを受け取る可能性があります。したがって、古いパスワードは削除されますが、新しいパスワードは設定されません。それは良くない。 「1つのトランザクション」でそれを行う方法はありますか? PS。リセットトークンを使用したResetPasswordAsyncメソッドを見て、より安全だと思われます(ユーザーが不安定な状況になることはないため)が、いずれにしても2アクションで実行されます。
ApplicationUserManager
は、ASP.NETテンプレートによって生成されたクラスです。
つまり、編集して、まだ持っていない機能を追加できます。 UserManagerクラスには、Store
という名前の保護されたプロパティがあり、UserStore
クラス(またはASP.NET Identityの構成方法またはカスタムユーザーストア実装を使用する場合はそのサブクラスへの参照)への参照を格納します、つまり、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);
}
}
UserManager
は、基になるUserStore
のラッパーにすぎません。使用可能なメソッドの MSDN でIUserPasswordStore
インターフェイスドキュメントを確認してください。
Edit:PasswordHasher
はUserManager
クラスのパブリックプロパティでもあります。 インターフェイスの定義はこちら =。
編集2:一部の人々は素朴に信じているので、できないこの方法でパスワード検証を行い、更新しました。 PasswordValidator
プロパティもUserManager
のプロパティであり、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();
}
編集:私はOPが1つのトランザクションでタスクを実行する回答を要求したことを知っていますが、コードは人々にとって有用だと思います。
すべての答えはPasswordHasherを直接使用しますが、機能の一部(検証など)が失われるため、お勧めできません。
別の方法(推奨される方法を想定します)では、パスワードリセットトークンを作成し、それを使用してパスワードを変更します。例:
var user = await UserManager.FindByIdAsync(id);
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
var result = await UserManager.ResetPasswordAsync(user, token, "MyN3wP@ssw0rd");
これは、@ 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
を使用する変更されたセットアップに特に適用されます。 <AppUser, int>
型の引数を削除するだけで、デフォルトのASP.NET Identityセットアップで動作するようになると思います。
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私は現在のログインユーザーから取得しています。
ユーザーの現在のパスワードがなく、パスワードを変更したい場合。代わりに、ユーザーのパスワードを削除してから、新しいパスワードを追加してください。この方法では、ユーザーの現在のパスワードを必要とせずにユーザーのパスワードを変更できます。
await UserManager.RemovePasswordAsync(user);
await UserManager.AddPasswordAsync(user, model.Password);
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");
}
}
}