84

管理者がユーザーのパスワードを変更する機能が必要です。したがって、管理者はユーザーの現在のパスワードを入力するべきではなく、新しいパスワードを設定できる必要があります。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 つのアクションで実行されます。

4

11 に答える 11

127

編集:OPが1つのトランザクションでタスクを実行する回答を要求したことは知っていますが、コードは人々にとって役立つと思います。

すべての回答は PasswordHasher を直接使用しますが、これはお勧めできません。組み込みの機能 (検証など) が失われるからです。

別の方法 (推奨される方法だと思います) は、パスワード リセット トークンを作成し、それを使用してパスワードを変更することです。例:

var user = await UserManager.FindByIdAsync(id);

var token = await UserManager.GeneratePasswordResetTokenAsync(user);

var result = await UserManager.ResetPasswordAsync(user, token, "MyN3wP@ssw0rd");
于 2017-08-16T14:07:31.657 に答える
44

ApplicationUserManagerASP.NET テンプレートによって生成されるクラスです。

つまり、編集して、まだない機能を追加できます。UserManager クラスには、 ASP.NET ID の構成方法に応じて、またはカスタム ユーザー ストア実装を使用する場合、つまり MySQL のような別のデータベース エンジンを使用する場合Storeに、クラス (またはそのサブクラス) への参照を格納するという名前の保護されたプロパティがあります。 UserStore)。

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。利用可能なメソッドについては、 MSDNIUserPasswordStoreのインターフェイス ドキュメントを参照してください。

編集: はクラスPasswordHasherのパブリック プロパティでもあります。ここでインターフェイス定義を参照してください。UserManager

編集 2: 一部の人々は素朴に信じているため、この方法ではパスワードの検証を行うことはできないため、更新しました。このPasswordValidatorプロパティはのプロパティでもあり、UserManager2行のコードを追加してパスワード検証も追加するだけです(ただし、これは元の質問の要件ではありませんでした)。

于 2015-03-27T00:56:53.983 に答える
7

これは、@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 セットアップで動作するようにするには、型引数を削除するだけでよいと思います。

于 2016-06-16T17:48:19.633 に答える
3
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 は、現在ログインしているユーザーから取得しています。

于 2017-11-16T03:07:17.417 に答える
-2

はい。それで合っています。トークンを介した ResetPassword は、推奨されるアプローチです。しばらく前に、.NET Identity の完全なラッパーを作成しました。コードはここにあります。お役に立てるかもしれません。nuget もここで見つけることができます。こちらのブログでもライブラリについて説明しました。このラッパーは nuget として簡単に使用でき、インストール中に必要な構成をすべて作成します。

于 2017-07-03T17:33:51.480 に答える