ASP.NET Identity reset password

如何在新的 ASP.NET 标识系统中获得用户的密码?或者如何在不知道当前密码(用户忘记密码)的情况下重置?

152091 次浏览
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);
}

This snippet of code is taken out of the AspNetIdentitySample project available on github

In current release

假设您已经处理了重置遗忘密码的请求验证,请使用以下代码作为示例代码步骤。

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 每夜构建

该框架将更新为与 Token 一起处理诸如 ForgetPassword 之类的请求。一旦发布,就需要简单的代码指导。

更新:

This update is just to provide more clear steps.

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

反对

这是最初的答案。有用,但有个问题。如果 AddPassword失败了怎么办?用户没有密码。

最初的答案是: 我们可以使用三行代码:

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 proposed丹尼尔 · 赖特后来解释说的答案。

在你的 UserManager上,第一个呼叫 GeneratePasswordResetTokenAsync。一旦用户验证了他的身份(例如通过电子邮件接收令牌) ,将令牌传递给 ResetPasswordAsync

或者如何在不知道当前密码(用户忘记密码)的情况下重置?

如果希望使用 UserManager 更改密码,但不希望提供用户的当前密码,则可以生成密码重置令牌,然后立即使用它。

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

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

在密码重置的情况下,建议通过发送密码重置令牌到注册用户的电子邮件,并要求用户提供新的密码重置。如果已经创建了一个易于使用。NET 库 over Identity 框架的默认配置设置。您可以在 github 的 博客链接源代码上找到详细信息。

我认为微软的 ASP.NET 身份指南是一个良好的开端。

Https://learn.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);
}

和欧文一起:

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

需要使用相同的名称创建 DpapiDataProtectionProviderDataProtectorTokenProvider,才能使密码重置起作用。使用 Owin 创建密码重置令牌,然后用另一个名称创建一个新的 DpapiDataProtectionProvider,这样做是行不通的。

我用于 ASP.NET 标识的代码:

网站配置:

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

我做了一些调查,找到了一个适合我的解决方案,这个解决方案是在这篇文章中找到的一些解决方案的混合体。

我基本上是在编译这个解决方案,并发布适合我的解决方案。在我的情况下,我不想使用来自。净核。

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


}

用于 Web API 的 Asp.Net 核心标识中重置密码的最佳方法。

注意 * < em > : 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);
}
}