快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码相关的知识,希望对你有一定的参考价值。

这是 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

密码重置

用户管理中最常见的功能就是密码重置。

密码重置过程,不应该涉及系统管理员,因为用户本身应该能够独立完成整个过程。

通常,登录页面上都会为用户提供忘记密码的链接,以用来重置密码,这就是我们接下来要实现的功能。

简单地解释一下密码重置过程:

  1. 用户单击忘记密码链接,然后跳转到带有电子邮件字段的页面。

  2. 用户填写该字段后,应用程序会向该电子邮件发送密码重置的连接。

  3. 用户通过单击电子邮件的密码重置链接,此时会使用密码重置令牌,重定向到密码重置页面。

  4. 用户填充表单中的所有字段后,应用程序将重置密码,用户再被重定向到登录页面或主页。

邮件服务

示例项目中已经集成了邮件服务 「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 身份认证框架 Identity - 通过邮件重置密码的主要内容,如果未能解决你的问题,请参考以下文章

快速掌握 ASP.NET 身份认证框架 Identity - 通过邮件重置密码

快速掌握 ASP.NET 身份认证框架 Identity - 用户注册

第16章 使用ASP.NET Core Identity

如何先用asp.net身份框架数据库将asp.net mvc迁移到asp.net core

ASP.net 身份框架 - 重新发送确认电子邮件

快速理解ASP.NET Core的认证与授权