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

如果喜欢我的文章,那么
在看和转发是对我最大的支持!
(戳下面蓝字阅读)
推荐关注微信公众号:码侠江湖
觉得不错,点个在看再走哟
边栏推荐
- USB DRIVER
- QIngScan使用
- TopoLVM: 基于LVM的Kubernetes本地持久化方案,容量感知,动态创建PV,轻松使用本地磁盘
- Quicksand painting simulator source code
- Getting started with Scala_ Immutable list and variable list
- 733. image rendering
- CVPR2021:Separating Skills and Concepts for Novel Visual Question Answering将技巧与概念分开的新视觉问答
- Uni-app 之uParse 富文本解析 完美解析富文本!
- 苹果手机证书构体知识
- [promise I] introduction of promise and key issues of hand rolling
猜你喜欢

2016Analyzing the Behavior of Visual Question Answering Models

2021:Beyond Question-Based Biases:Assessing Multimodal Shortcut Learning in Visual Question Answeri

Pat grade a 1026 table tennis

Stack overflow vulnerability

敏捷开发篇--Agile Development-自用

JMeter distributed pressure measurement

2021:Graphhopper: Multi-Hop Scene Graph Reasoning for Visual Question Answering

QIngScan使用

Topolvm: kubernetes local persistence scheme based on LVM, capacity aware, dynamically create PV, and easily use local disk

2019LXMERT:Learning Cross-Modality Encoder Representations from Transformers
随机推荐
ERP需求和销售管理 金蝶
人群模拟
Overview of Tsinghua & Huawei | semantic communication: Principles and challenges
静态时序分析-OCV和time derate
How do I simplify the development of interfaces in open source systems?
Cs5213 HDMI to VGA (with audio) single turn scheme, cs5213 HDMI to VGA (with audio) IC
Paddlepaddle 21 is implemented based on dropout with 4 lines of code droplock
PAT甲级 1023 Have Fun with Numbers
Nestjs environment variable configuration to solve the problem of how to inject services into interceptors
记录unity 自带读取excel的方法和遇到的一些坑的解决办法
2016Analyzing the Behavior of Visual Question Answering Models
Human soberness: bottom logic and top cognition
事业观、金钱观与幸福观
MySQL development environment
Pat grade a 1018 public bike management
JMeter distributed pressure measurement
2021:Passage Retrieval for Outside-KnowledgeVisual Question Answering通道检索的外部知识视觉问答
Pat class a 1024 palindromic number
Nacos调用微服务两个问题:1.Load balancer does not contain an instance for the service 2.Connection refused
敏捷开发篇--Agile Development-自用