![](/img/trans.png)
[英]How To Change Password Validation in ASP.Net MVC Identity 2 - Part 2
[英]ASP.NET Identity change password
我需要能夠由管理員更改用戶密碼。 所以,admin 不應該輸入用戶的當前密碼,他應該有能力設置一個新密碼。 我查看了 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 方法上收到錯誤。 因此,舊密碼將被刪除,但不會設置新密碼。 這樣不好。 有沒有辦法在“一次交易”中做到這一點? 附注。 我看到了帶有重置令牌的 ResetPasswordAsync 方法,似乎它更安全(因為用戶不會出現不穩定的情況),但無論如何,它通過 2 個操作來完成。
編輯:我知道 OP 要求在一個事務中執行任務的答案,但我認為該代碼對人們有用。
所有答案都直接使用 PasswordHasher 這不是一個好主意,因為您將失去一些烘焙功能(驗證等)。
另一種方法(我假設推薦的方法)是創建一個密碼重置令牌,然后使用它來更改密碼。 例子:
var user = await UserManager.FindByIdAsync(id);
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
var result = await UserManager.ResetPasswordAsync(user, token, "MyN3wP@ssw0rd");
這種方法對我有用:
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();
}
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
接口文檔。
編輯: PasswordHasher
也是UserManager
類的公共屬性,請參閱此處的接口定義。
編輯2:由於有些人天真地相信,您不能以這種方式進行密碼驗證,因此我對其進行了更新。 PasswordValidator
屬性也是UserManager
一個屬性,它就像添加 2 行代碼來添加密碼驗證一樣簡單(盡管這不是原始問題的要求)。
在 .net 核心 3.0 中
var token = await UserManager.GeneratePasswordResetTokenAsync(user);
var result = await UserManager.ResetPasswordAsync(user, token, password);
這只是對@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);
對於ASP.NET Core 3.1
用戶,這是@Tseng 和@BCA 提供的優秀答案的現代化迭代。
PasswordValidator
不再是UserManager
上的屬性 - 相反,該屬性是IList PasswordValidators
。 此外,Identity 現在有一個protected UpdatePasswordHash
方法,它可以為您更改密碼,而無需直接訪問UserStore
,這消除了手動散列和保存密碼的需要。
UserManager
還有一個公共屬性bool SupportsUserPassword
,它取代了測試Store
實現IUserPasswordStore
的需要(在內部,這正是UserManager
在SupportsUserPassword
getter 中所做的)。
由於UpdatePasswordHash
protected
,您仍然需要擴展基本UserManager
。 它的簽名是:
protected Task<IdentityResult> UpdatePasswordHash(TUser user, string newPassword, bool validatePassword)
其中validatePassword
表示是否運行密碼驗證。 這並不默認為true
,不幸的是,所以它需要供給。 實現如下所示:
public async Task<IdentityResult> ChangePasswordAsync(ApplicationUser user, string newPassword)
{
if (!SupportsUserPassword)
{
return IdentityResult.Failed(new IdentityError
{
Description = "Current UserStore doesn't implement IUserPasswordStore"
});
}
var result = await UpdatePasswordHash(user, newPassword, true);
if (result.Succeeded)
await UpdateAsync(user);
return result;
}
和以前一樣,首要任務是確保當前的UserStore
支持密碼。
然后,只需使用ApplicationUser
、新密碼和true
調用UpdatePasswordHash
以通過驗證更新該用戶的密碼。 如果更新成功,您仍然需要保存用戶,因此調用UpdateAsync
。
我認為解決方案要容易得多
public async Task<IdentityResult> ResetPasswordAsync(ApplicationUser user, string password) { string token = await userManager.GeneratePasswordResetTokenAsync(user); return await userManager.ResetPasswordAsync(user, token, 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");
}
}
}
public async Task<ActionResult> ResetUserPassword(string id, string Password)
{
// Find User
var user = await context.Users.Where(x => x.Id == id).SingleOrDefaultAsync();
if (user == null)
{
return RedirectToAction("UserList");
}
await UserManager.RemovePasswordAsync(id);
// Add a user password only if one does not already exist
await UserManager.AddPasswordAsync(id, Password);
return RedirectToAction("UserDetail", new { id = id });
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.