当前位置:网站首页>快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码
快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码
2022-06-27 03:37:00 【dotNET跨平台】
这是 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」 方法,执行密码重置操作。
如果操作失败,就向模型状态添加错误并返回视图。否则,我们将用户重定向到确认页面。
需要注意的是,如果想要测试最终效果,邮件服务的配置以及用户的邮件地址都必须是真实有效的。
小结
现在,我们已经实现了用户通过电子邮件,重置密码的功能,下篇文章将会讲解如何在用户注册时,必须确认电子邮件是否有效的功能。
更多精彩内容,请关注我▼▼

如果喜欢我的文章,那么
在看和转发是对我最大的支持!
(戳下面蓝字阅读)
推荐关注微信公众号:码侠江湖
觉得不错,点个在看再走哟
边栏推荐
- Mmdetection valueerror: need at least one array to concatenate solution
- 元透实盘周记20220627
- Career outlook, money outlook and happiness outlook
- Interview-01
- 测试nohup和&的各自作用
- PAT甲级 1023 Have Fun with Numbers
- A^2=E | 方程的解 | 这个方程究竟能告诉我们什么
- Further exploration of handler (Part 2) (the most complete analysis of the core principles of handler)
- Anaconda3安装过程及安装后缺失大量文件,没有scripts等目录
- NestJS环境变量配置,解决如何在拦截器(interceptor)注入服务(service)的问题
猜你喜欢

元透实盘周记20220627

Geometric distribution (a discrete distribution)

How does the brain do arithmetic? Both addition and subtraction methods have special neurons, and the symbol text can activate the same group of cell sub journals

MySql的开发环境

Resnet152 pepper pest image recognition 1.0

PAT甲级 1025 PAT Ranking

电商产品如何在知乎上进行推广和打广告?

CVPR2021:Separating Skills and Concepts for Novel Visual Question Answering将技巧与概念分开的新视觉问答

GAMES101作业7提高-微表面材质的实现过程

ESP8266
随机推荐
一文教你Kali信息收集
Promise [II. Promise source code] [detailed code comments / complete test cases]
如何系统学习LabVIEW?
Pat grade a 1019 general palindromic number
Getting started with Scala_ Immutable list and variable list
GAMES101作业7提高-微表面材质的实现过程
流沙画模拟器源码
Static timing analysis OCV and time derive
Stack overflow vulnerability
Games101 job 7 improvement - implementation process of micro surface material
servlet与JSP期末复习考点梳理 42问42答
Resnet152 pepper pest image recognition 1.0
Products change the world
Pat grade a 1021 deep root
2021:Beyond Question-Based Biases:Assessing Multimodal Shortcut Learning in Visual Question Answeri
Questions and answers of chlor alkali electrolysis process in 2022
2022茶艺师(高级)上岗证题库模拟考试平台操作
手机新领域用法知识
苹果唯一图谱架构常识
Nestjs environment variable configuration to solve the problem of how to inject services into interceptors