1. ホーム
  2. c#

[解決済み] ASP.NET Identity のパスワード変更

2023-05-15 19:43:32

質問

管理者がユーザーのパスワードを変更する機能が必要です。そのため、管理者はユーザーの現在のパスワードを入力するのではなく、新しいパスワードを設定する機能を持つ必要があります。私は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 Templateで生成されるクラスです。

つまり、あなたはこれを編集して、まだ持っていない機能を追加することができます。UserManager クラスには Store という名前の protected プロパティがあり、このプロパティには 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 . チェックアウト IUserPasswordStore インターフェースのドキュメントを MSDN にある、利用可能なメソッドに関するドキュメントを参照してください。

編集します。 その PasswordHasher はまた、パブリックプロパティとして UserManager クラスのパブリックプロパティです。 インターフェース定義はこちら .

2を編集します。 一部の人が 素直に を信じ込んでいる人がいるので、アップデートしてみました。その PasswordValidator プロパティも UserManager であり、パスワードバリデーションを追加するために2行のコードを追加するのと同じくらい簡単です(これは最初の質問の要件ではありませんでしたが)。