這是 ASP.NET Core Identity 系列的第四篇文章,上一篇文章講解了如何在 ASP.NET Core Identity 中實現用戶登錄與登出。
這篇文章講一講如何在 ASP.NET Core Identity 中通過郵件服務實現用戶賬號的密碼重置。
點擊上方或后方藍字,閱讀 ASP.NET Core Identity 系列合集。
本篇文章的示例項目:https://github.com/zilor-net/IdentitySample/tree/main/Sample04
密碼重置
用戶管理中最常見的功能就是密碼重置。
密碼重置過程,不應該涉及系統管理員,因為用戶本身應該能夠獨立完成整個過程。
通常,登錄頁面上都會為用戶提供忘記密碼的鏈接,以用來重置密碼,這就是我們接下來要實現的功能。
簡單地解釋一下密碼重置過程:
用戶單擊忘記密碼鏈接,然后跳轉到帶有電子郵件字段的頁面。
用戶填寫該字段后,應用程序會向該電子郵件發送密碼重置的連接。
用戶通過單擊電子郵件的密碼重置鏈接,此時會使用密碼重置令牌,重定向到密碼重置頁面。
用戶填充表單中的所有字段后,應用程序將重置密碼,用戶再被重定向到登錄頁面或主頁。
郵件服務
示例項目中已經集成了郵件服務 「EmailService」 ,以用來幫助我們發送郵件,
具體的郵件發送的實現不是這個系列的主題,就不做過多的闡述。大家可以自己查看示例中「EmailService」項目中關于郵件發送的代碼。
郵件服務通過擴展方法注冊到了依賴注入框架中,其具體配置在 「appsettings.json」 中。
忘記密碼
首先,我們需要創建 「忘記密碼」 的視圖。
在 「Models」 文件夾中,創建一個 「ForgotPasswordModel」 類:
public?class?ForgotPasswordModel
{[Display(Name?=?"電子郵箱")][Required(ErrorMessage?=?"電子郵箱不能為空")][EmailAddress(ErrorMessage?=?"電子郵箱格式不正確")]public?string?Email?{?get;?set;?}
}
它會用在「忘記密碼」視圖中,這里我們只需要獲取用戶的電子郵件,所以這里只有一個 「Email」 屬性。
接下來,在 「Account」 控制器中,創建兩個操作方法:
[HttpGet]
public?IActionResult?ForgotPassword()
{return?View();
}[HttpPost]
[ValidateAntiForgeryToken]
public?async?Task<IActionResult>?ForgotPassword(ForgotPasswordModel?forgotPasswordModel)
{return?View(forgotPasswordModel);
}public?IActionResult?ForgotPasswordConfirmation()
{return?View();
}
這個套路我們已經很熟悉了,第一個 「ForgotPassword」 只是為了創建視圖;第二個 「ForgotPassword」 是為了實現邏輯;「ForgotPasswordConfirmation」 則是返回確認視圖。
接下來,再依次創建相關的視圖:

<h1>ForgotPasswordConfirmation</h1><p>重置密碼的鏈接已經發送到您的電子郵箱!
</p>
然后在 「Login」 視圖中,添加忘記密碼的鏈接:
<div?class="form-group"><a?asp-action="ForgotPassword">忘記密碼</a>
</div>
現在,讓我們來實現忘記密碼的邏輯:
[HttpPost]
[ValidateAntiForgeryToken]
public?async?Task<IActionResult>?ForgotPassword([FromServices]IEmailSender?emailSender,?ForgotPasswordModel?forgotPasswordModel)
{if?(!ModelState.IsValid)return?View(forgotPasswordModel);var?user?=?await?_userManager.FindByEmailAsync(forgotPasswordModel.Email);if?(user?==?null)return?RedirectToAction(nameof(ForgotPasswordConfirmation));var?token?=?await?_userManager.GeneratePasswordResetTokenAsync(user);var?callback?=?Url.Action(nameof(ResetPassword),?"Account",?new?{?token,?email?=?user.Email?},?Request.Scheme);var?message?=?new?Message(new?string[]?{?user.Email?},?"重置密碼",?callback,?null);await?emailSender.SendEmailAsync(message);return?RedirectToAction(nameof(ForgotPasswordConfirmation));
}
如果模型有效,就通過用戶的電子郵件,從數據庫中獲取用戶。
如果不存在,只需將該用戶,重定向到郵件已發送的確認頁面,而不是創建用戶不存在的消息。
這么做主要是出于安全考慮,以防止有人利用這個功能,驗證用戶名的有效性。
如果用戶存在,就通過 「GeneratePasswordResetTokenAsync」 方法,生成一個令牌,并創建一個回調鏈接,到我們將用于重置密碼邏輯的操作。
最后,我們向用戶提供的電子郵件,發送郵件消息,并將用戶重定向到確認頁面。
現在,程序還無法創建令牌,因為我們還沒有注冊令牌服務,這需要在注冊 「Identity」 方法時進行注冊:
builder.Services.AddIdentity<User,?IdentityRole>().AddEntityFrameworkStores<ApplicationContext>().AddDefaultTokenProviders();
如果我們希望密碼重置令牌只在有限的時間內有效,例如: 2小時,那我們還需要配置令牌生存期:
builder.Services.Configure<DataProtectionTokenProviderOptions>(opt?=>opt.TokenLifespan =?TimeSpan.FromHours(2));
重置密碼
接著,我們來實現 「ResetPassword」 重置密碼的操作方法,創建一個 「ResetPasswordModel」 類:
public?class?ResetPasswordModel
{[Display(Name?=?"密碼")][Required(ErrorMessage?=?"密碼不能為空")][DataType(DataType.Password)]public?string?Password?{?get;?set;?}[Display(Name?=?"確認密碼")][DataType(DataType.Password)][Compare("Password",?ErrorMessage?=?"密碼與確認密碼不匹配。")]public?string?ConfirmPassword?{?get;?set;?}public?string?Email?{?get;?set;?}public?string?Token?{?get;?set;?}
}
然后,在 「Account」 控制器中,創建 「ResetPassword」 操作方法:
[HttpGet]
public?IActionResult?ResetPassword(string?token,?string?email)
{var?model?=?new?ResetPasswordModel?{?Token?=?token,?Email?=?email?};return?View(model);
}[HttpPost]
[ValidateAntiForgeryToken]
public?async?Task<IActionResult>?ResetPassword(ResetPasswordModel?resetPasswordModel)
{return?View();
}[HttpGet]
public?IActionResult?ResetPasswordConfirmation()
{return?View();
}
這里與 「ForgotPassword」 操作類似。
「HttpGet」ResetPassword
操作會接受來自電子郵件中,密碼重置連接的請求,提取令牌和電子郵件,并創建一個視圖。
「HttpPost」ResetPassword
操作是處理重置密碼的邏輯。
ResetPasswordConfirmation
只是一個密碼重置的確認視圖。
依次創建這些視圖:

需要注意的是,我們需要把 「Email」 和 「Token」 兩個字段隱藏起來,因為這兩個值由應用提供,不需要用戶設置:
<input?type="hidden"?asp-for="Email"?class="form-control"?/>
<input?type="hidden"?asp-for="Token"?class="form-control"?/>
「ResetPasswordConfirmation」 視圖:
<h1>ResetPasswordConfirmation</h1>
<p>您的密碼已經重置.?請點擊這里?<a?asp-action="Login">?登錄?</a>!
</p>
最后,再來修改 「POST」ResetPassword
操作方法:
[HttpPost]
[ValidateAntiForgeryToken]
public?async?Task<IActionResult>?ResetPassword(ResetPasswordModel?resetPasswordModel)
{if?(!ModelState.IsValid)return?View(resetPasswordModel);var?user?=?await?_userManager.FindByEmailAsync(resetPasswordModel.Email);if?(user?==?null)RedirectToAction(nameof(ResetPasswordConfirmation));var?resetPassResult?=?await?_userManager.ResetPasswordAsync(user,?resetPasswordModel.Token,?resetPasswordModel.Password);if(!resetPassResult.Succeeded){foreach?(var?error?in?resetPassResult.Errors){ModelState.TryAddModelError(error.Code,?error.Description);}return?View();}return?RedirectToAction(nameof(ResetPasswordConfirmation));
}
首先,檢查模型的有效性,以及用戶是否存在于數據庫中。
之后,使用 「ResetPasswordAsync」 方法,執行密碼重置操作。
如果操作失敗,就向模型狀態添加錯誤并返回視圖。否則,我們將用戶重定向到確認頁面。
需要注意的是,如果想要測試最終效果,郵件服務的配置以及用戶的郵件地址都必須是真實有效的。
小結
現在,我們已經實現了用戶通過電子郵件,重置密碼的功能,下篇文章將會講解如何在用戶注冊時,必須確認電子郵件是否有效的功能。
更多精彩內容,請關注我▼▼
如果喜歡我的文章,那么
在看和轉發是對我最大的支持!
(戳下面藍字閱讀)
ASP.NET 6 中間件系列
?ASP.NET 6 身份認證框架 Identity 系列
查缺補漏系統學習 EF Core 6? 系列
推薦關注微信公眾號:碼俠江湖
? ? ? ? ? ? ? ? ? ? ? ??覺得不錯,點個在看再走喲