ASP.NET Identityのリセットパスワード


95

新しいASP.NET Identityシステムでユーザーのパスワードを取得するにはどうすればよいですか?または、現在のパスワード(ユーザーがパスワードを忘れた)を知らずにリセットするにはどうすればよいですか?

回答:


102

現在のリリースでは

忘れたパスワードをリセットする要求の検証を処理したと想定して、サンプルコードの手順として次のコードを使用します。

ApplicationDbContext =new ApplicationDbContext()
String userId = "<YourLogicAssignsRequestedUserId>";
String newPassword = "<PasswordAsTypedByUser>";
ApplicationUser cUser = UserManager.FindById(userId);
String hashedNewPassword = UserManager.PasswordHasher.HashPassword(newPassword);
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>();            
store.SetPasswordHashAsync(cUser, hashedNewPassword);

AspNetナイトリービルド

フレームワークは、ForgetPasswordなどのリクエストを処理するためにトークンと連動するように更新されています。リリース後は、簡単なコードガイダンスが期待されます。

更新:

このアップデートは、より明確な手順を提供するためのものです。

ApplicationDbContext context = new ApplicationDbContext();
UserStore<ApplicationUser> store = new UserStore<ApplicationUser>(context);
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(store);
String userId = User.Identity.GetUserId();//"<YourLogicAssignsRequestedUserId>";
String newPassword = "test@123"; //"<PasswordAsTypedByUser>";
String hashedNewPassword = UserManager.PasswordHasher.HashPassword(newPassword);                    
ApplicationUser cUser = await store.FindByIdAsync(userId);
await store.SetPasswordHashAsync(cUser, hashedNewPassword);
await store.UpdateAsync(cUser);

バージョン1.1がいつリリースされるか知っていますか?
graycrow 2013年

まだアルファ版であり、1.0がリリースされたばかりです。したがって、何ヶ月も想定します。myget.org/gallery/aspnetwebstacknightly
jd4u

11
奇妙なことに、store.SetPasswordHashAsync(cUser、hashedNewPassword)メソッドの呼び出しは機能しませんでした。代わりに、cUser.PasswordHash = hashedNewPasswordを手動で設定してから、UserManager.UpdateAsync(user);を呼び出す必要がありました。
アンディMehalick 2013年

1
コードが機能しないのは、ユーザー取得コンテキストとストアコンテキストが異なる場合のみです。コードはサンプルのステップにすぎず、正確ではありませんでした。他の人のためにこの問題を回避するためにすぐに答えを更新します。
jd4u 2013年

1
フレームワーク1は提供しません。ただし、Framework 2-alphaには、パスワードのリセット要求を処理するための簡単なプロセスを提供できる機能がほとんどありません。aspnetidentity.codeplex.com
jd4u

137

または、現在のパスワード(ユーザーがパスワードを忘れた)を知らずにリセットするにはどうすればよいですか?

UserManagerを使用してパスワードを変更したいが、ユーザーの現在のパスワードを提供したくない場合は、パスワードリセットトークンを生成してすぐに使用できます。

string resetToken = await UserManager.GeneratePasswordResetTokenAsync(model.Id);
IdentityResult passwordChangeResult = await UserManager.ResetPasswordAsync(model.Id, resetToken, model.NewPassword);

8
これは、新しいパスワードを設定するための最善かつ最もクリーンな方法です。受け入れられた回答の問題は、パスワードハッシャーに直接アクセスすることにより、パスワードの複雑さの検証をバイパスすることです。
クリス、

6
Fyi、「IUserTokenProviderが登録されていません」というエラーが表示される場合があります。上記のロジックを使用する場合。このstackoverflow.com/questions/22629936/…を参照してください。
Prasad Kanaparthi

1
これは、バージョン2のMicrosoft.AspNet.Identityでのみ機能すると思います。あなたは、バージョン1でGeneratePasswordResetTokenAsync方法を見つけることができません
romanoza

お返事ありがとうございます。それは私にとって魅力のように機能します。
Thomas.Benz 2017年

4
Invalid Tokenを取得した場合SecurityStampは、ユーザーのがnullでないことを確認してください。これは、他のデータベースから移行されたユーザー、またはUserManager.CreateAsync()メソッドで作成されなかったユーザーに対して発生する可能性があります。
Alisson

70

非推奨

これが元の答えでした。動作しますが、問題があります。AddPassword失敗した場合はどうなりますか?ユーザーはパスワードなしで残されます。

元の答え:3行のコードを使用できます。

UserManager<IdentityUser> userManager = 
    new UserManager<IdentityUser>(new UserStore<IdentityUser>());

userManager.RemovePassword(userId);

userManager.AddPassword(userId, newPassword);

参照:http : //msdn.microsoft.com/en-us/library/dn457095(v=vs.111).aspx

今おすすめ

その答えを使用することをお勧めおそらくだEdwardBreyを提案し、その後DanielWrightは後で詳述コードサンプルで。


1
これを神に感謝します。これを見るまでは、新しいユーザーストアを作成する必要があると思いました。
ルーク

これをSQLで直接行う方法はありますか?実行可能ファイルの代わりに、必要なときに呼び出すsprocをDBAに渡したいと思います。
マークリッチマン

@MarkRichmanそれは新しい質問です。ただし、SQL Serverで実行される生成されたT-SQLを検査することもできます。
Shaun Luttin、2015

3
これに注意してください。AddPasswordが失敗した場合(つまり、パスワードの複雑さが不十分な場合)は、ユーザーはパスワードなしで残されます。
Chris

1
ダニエルライトが提案したのは、ビジネスルールをバイパスせずに最もクリーンなアプローチ(パスワードハッシャーに直接アクセスすると、パスワードの複雑さの検証がないため)です。
クリス

29

UserManager、最初にGeneratePasswordResetTokenAsyncを呼び出します。ユーザーが自分の身元を確認したら(たとえば、電子メールでトークンを受信するなどして)、トークンをResetPasswordAsyncに渡します。


1
ResetPasswordAsyncがユーザーIDを必要とする理由と、トークンが表示されたときにユーザーからIDを取得するための合理的な方法を理解しようとしています。GeneratePasswordResetは150文字を超えるトークンを使用します...ユーザーIDを暗号化して格納するにはそれで十分なので、自分で実装する必要はありません。:(
pettys 2015

ユーザーIDを要求しているため、そのユーザーIDに対してリセットトークンをIDデータベースに入力できると思います。これを行わなかった場合、フレームワークはトークンが有効であるかどうかをどのようにして知るでしょうか。User.Identity.GetUserId()などを使用してユーザーIDをプルできるはずです。
Ryan Buddicom、2015年

1
ユーザーIDを要求することは、APIの部分ではばかげた選択です。ResetPassword(async)が呼び出されたとき、トークンはすでにデータベースにあり、入力に対して検証するだけで十分です。
フィリップ2015

@Filip、ResetPasswordAsyncユーザーIDを使用する利点は、IDプロバイダーがユーザーIDをインデックス化するだけでよく、トークンもインデックス化する必要がないことです。これにより、ユーザー数が多い場合のスケーリングが向上します。
Edward Brey 2015

1
@Edward Brey、リセットコールのユーザーIDをどのように取得しますか?
Filip

2
string message = null;
//reset the password
var result = await IdentityManager.Passwords.ResetPasswordAsync(model.Token, model.Password);
if (result.Success)
{
    message = "The password has been reset.";
    return RedirectToAction("PasswordResetCompleted", new { message = message });
}
else
{
    AddErrors(result);
}

このコードスニペットは、githubで利用可能な AspNetIdentitySampleプロジェクトから取り出されたものです


2

メソッドを作成 UserManager<TUser, TKey>

public Task<IdentityResult> ChangePassword(int userId, string newPassword)
{
     var user = Users.FirstOrDefault(u => u.Id == userId);
     if (user == null)
          return new Task<IdentityResult>(() => IdentityResult.Failed());

     var store = Store as IUserPasswordStore<User, int>;
     return base.UpdatePassword(store, user, newPassword);
}

1

パスワードをリセットする場合は、パスワードリセットトークンを登録ユーザーのメールに送信してリセットし、ユーザーに新しいパスワードを入力するよう依頼することをお勧めします。デフォルトの構成設定で、Identityフレームワーク上に簡単に使用できる.NETライブラリを作成した場合。詳細については、ブログのリンクソースコードの github をご覧ください。


1

ASP.NET IdentityのMicrosoftガイドは良い出発点だと思います。

https://docs.microsoft.com/en-us/aspnet/identity/overview/features-api/account-confirmation-and-password-recovery-with-aspnet-identity

注意:

AccountControllerを使用せず、パスワードをリセットしたくない場合は、を使用してくださいRequest.GetOwinContext().GetUserManager<ApplicationUserManager>();。同じOwinContextがない場合は、使用するのと同じDataProtectorTokenProviderように新しいものを作成する必要がありOwinContextます。デフォルトではを見てくださいApp_Start -> IdentityConfig.cs。のようになりnew DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));ます。

次のように作成できます:

オーウィンなし:

[HttpGet]
[AllowAnonymous]
[Route("testReset")]
public IHttpActionResult TestReset()
{
    var db = new ApplicationDbContext();
    var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(db));
    var provider = new DpapiDataProtectionProvider("SampleAppName");
    manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
        provider.Create("SampleTokenName"));

    var email = "test@test.com";

    var user = new ApplicationUser() { UserName = email, Email = email };

    var identityUser = manager.FindByEmail(email);

    if (identityUser == null)
    {
        manager.Create(user);
        identityUser = manager.FindByEmail(email);
    }

    var token = manager.GeneratePasswordResetToken(identityUser.Id);
    return Ok(HttpUtility.UrlEncode(token));
}

[HttpGet]
[AllowAnonymous]
[Route("testReset")]
public IHttpActionResult TestReset(string token)
{
    var db = new ApplicationDbContext();
    var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(db));
    var provider = new DpapiDataProtectionProvider("SampleAppName");
    manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
        provider.Create("SampleTokenName"));
    var email = "test@test.com";
    var identityUser = manager.FindByEmail(email);
    var valid = Task.Run(() => manager.UserTokenProvider.ValidateAsync("ResetPassword", token, manager, identityUser)).Result;
    var result = manager.ResetPassword(identityUser.Id, token, "TestingTest1!");
    return Ok(result);
}

Owinの場合:

[HttpGet]
[AllowAnonymous]
[Route("testResetWithOwin")]
public IHttpActionResult TestResetWithOwin()
{
    var manager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();

    var email = "test@test.com";

    var user = new ApplicationUser() { UserName = email, Email = email };

    var identityUser = manager.FindByEmail(email);

    if (identityUser == null)
    {
        manager.Create(user);
        identityUser = manager.FindByEmail(email);
    }

    var token = manager.GeneratePasswordResetToken(identityUser.Id);
    return Ok(HttpUtility.UrlEncode(token));
}

[HttpGet]
[AllowAnonymous]
[Route("testResetWithOwin")]
public IHttpActionResult TestResetWithOwin(string token)
{
    var manager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();

    var email = "test@test.com";
    var identityUser = manager.FindByEmail(email);
    var valid = Task.Run(() => manager.UserTokenProvider.ValidateAsync("ResetPassword", token, manager, identityUser)).Result;
    var result = manager.ResetPassword(identityUser.Id, token, "TestingTest1!");
    return Ok(result);
}

DpapiDataProtectionProviderそしてDataProtectorTokenProvider仕事にパスワードリセットのために同じ名前で作成する必要があります。Owinを使用してパスワードリセットトークンを作成し、DpapiDataProtectionProvider別の名前で新しいトークンを作成することはできません。

ASP.NET Identityに使用するコード:

Web.Config:

<add key="AllowedHosts" value="example.com,example2.com" />

AccountController.cs:

[Route("RequestResetPasswordToken/{email}/")]
[HttpGet]
[AllowAnonymous]
public async Task<IHttpActionResult> GetResetPasswordToken([FromUri]string email)
{
    if (!ModelState.IsValid)
        return BadRequest(ModelState);

    var user = await UserManager.FindByEmailAsync(email);
    if (user == null)
    {
        Logger.Warn("Password reset token requested for non existing email");
        // Don't reveal that the user does not exist
        return NoContent();
    }

    //Prevent Host Header Attack -> Password Reset Poisoning. 
    //If the IIS has a binding to accept connections on 80/443 the host parameter can be changed.
    //See https://security.stackexchange.com/a/170759/67046
    if (!ConfigurationManager.AppSettings["AllowedHosts"].Split(',').Contains(Request.RequestUri.Host)) {
            Logger.Warn($"Non allowed host detected for password reset {Request.RequestUri.Scheme}://{Request.Headers.Host}");
            return BadRequest();
    }

    Logger.Info("Creating password reset token for user id {0}", user.Id);

    var host = $"{Request.RequestUri.Scheme}://{Request.Headers.Host}";
    var token = await UserManager.GeneratePasswordResetTokenAsync(user.Id);
    var callbackUrl = $"{host}/resetPassword/{HttpContext.Current.Server.UrlEncode(user.Email)}/{HttpContext.Current.Server.UrlEncode(token)}";

    var subject = "Client - Password reset.";
    var body = "<html><body>" +
               "<h2>Password reset</h2>" +
               $"<p>Hi {user.FullName}, <a href=\"{callbackUrl}\"> please click this link to reset your password </a></p>" +
               "</body></html>";

    var message = new IdentityMessage
    {
        Body = body,
        Destination = user.Email,
        Subject = subject
    };

    await UserManager.EmailService.SendAsync(message);

    return NoContent();
}

[HttpPost]
[Route("ResetPassword/")]
[AllowAnonymous]
public async Task<IHttpActionResult> ResetPasswordAsync(ResetPasswordRequestModel model)
{
    if (!ModelState.IsValid)
        return NoContent();

    var user = await UserManager.FindByEmailAsync(model.Email);
    if (user == null)
    {
        Logger.Warn("Reset password request for non existing email");
        return NoContent();
    }            

    if (!await UserManager.UserTokenProvider.ValidateAsync("ResetPassword", model.Token, UserManager, user))
    {
        Logger.Warn("Reset password requested with wrong token");
        return NoContent();
    }

    var result = await UserManager.ResetPasswordAsync(user.Id, model.Token, model.NewPassword);

    if (result.Succeeded)
    {
        Logger.Info("Creating password reset token for user id {0}", user.Id);

        const string subject = "Client - Password reset success.";
        var body = "<html><body>" +
                   "<h1>Your password for Client was reset</h1>" +
                   $"<p>Hi {user.FullName}!</p>" +
                   "<p>Your password for Client was reset. Please inform us if you did not request this change.</p>" +
                   "</body></html>";

        var message = new IdentityMessage
        {
            Body = body,
            Destination = user.Email,
            Subject = subject
        };

        await UserManager.EmailService.SendAsync(message);
    }

    return NoContent();
}

public class ResetPasswordRequestModel
{
    [Required]
    [Display(Name = "Token")]
    public string Token { get; set; }

    [Required]
    [Display(Name = "Email")]
    public string Email { get; set; }

    [Required]
    [StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 10)]
    [DataType(DataType.Password)]
    [Display(Name = "New password")]
    public string NewPassword { get; set; }

    [DataType(DataType.Password)]
    [Display(Name = "Confirm new password")]
    [Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
    public string ConfirmPassword { get; set; }
}

1

私は少し調査をしました、そして私のために働く解決策はこの投稿で設立されたいくつかの解決策の組み合わせでした。

私は基本的にこのソリューションをコンパイルしており、私にとって有効なものを投稿しています。私の場合、.netコアのトークンを使用したくありません。

public async Task ResetPassword(string userId, string password)
{
    var user = await _userManager.FindByIdAsync(userId);
    var hashPassword= _userManager.PasswordHasher.HashPassword(user, password);
    user.PasswordHash = passwordHash;
    await _userManager.UpdateAsync(user);

}

0

Asp.Net Core Identityでパスワードをリセットする最良の方法は、Web APIで使用します。

* :Error()およびResult()は内部使用のために作成されます。あなたが欲しいあなたを返すことができます。

        [HttpPost]
        [Route("reset-password")]
        public async Task<IActionResult> ResetPassword(ResetPasswordModel model)
        {
            if (!ModelState.IsValid)
                return BadRequest(ModelState);
            try
            {
                if (model is null)
                    return Error("No data found!");


                var user = await _userManager.FindByIdAsync(AppCommon.ToString(GetUserId()));
                if (user == null)
                    return Error("No user found!");

                Microsoft.AspNetCore.Identity.SignInResult checkOldPassword =
                    await _signInManager.PasswordSignInAsync(user.UserName, model.OldPassword, false, false);

                if (!checkOldPassword.Succeeded)
                    return Error("Old password does not matched.");

                string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);
                if (string.IsNullOrEmpty(resetToken))
                    return Error("Error while generating reset token.");

                var result = await _userManager.ResetPasswordAsync(user, resetToken, model.Password);

                if (result.Succeeded)
                    return Result();
                else
                    return Error();
            }
            catch (Exception ex)
            {
                return Error(ex);
            }
        }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.