ASP.NET Core Identity 框架中实现密码重置
文章目录
- 前言
- 一、密码重置流程原理
- 二、实现步骤
- 1)安装 NuGet 包
- 2)配置邮箱(示例使用 MailKit )
- 3)实现邮件发送类
- 4)注册服务
- 5)创建密码重置端点(控制器Controller)
- 三、关键注意事项
- 1)授权码获取
- 2)端口选择
- 3)编码问题
- 4)异常处理
- 四、常见问题排查
- 总结
前言
密码重置功能
一、密码重置流程原理
- 核心步骤:
- 用户请求重置密码(提供注册邮箱/用户名)
- 系统生成密码重置令牌并发送到用户邮箱
- 用户点击邮件中的链接,进入密码重置页面
- 提交新密码和令牌,系统验证并更新密码
- 关键技术:
- UserManager.GeneratePasswordResetTokenAsync() - 生成加密令牌
- UserManager.ResetPasswordAsync() - 验证令牌并更新密码
- 邮件服务集成(SMTP 或第三方服务)
二、实现步骤
1)安装 NuGet 包
- 安装MailKit
Install-Package MailKit
2)配置邮箱(示例使用 MailKit )
-
appsettings.json
"EmailSettings": {"SmtpServer": "smtp.163.com","Port": 465, //465"UserName": "XXX@163.com","Password": "DJgaznENCZByW4kW", //16位授权码(qq邮箱授权码或网易邮箱授权码,不是邮箱密码)"FromAddress": "XXX@163.com"}
-
EmailSettings.cs邮箱配置类
namespace IdentityProject.Entity {public class EmailSettings{public string SmtpServer { get; set; }public int Port { get; set; }public string UserName { get; set; }public string Password { get; set; }public string FromAddress { get; set; }} }
3)实现邮件发送类
- 代码如下(示例):
using IdentityProject.Entity; using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.Extensions.Options; using MimeKit; using System.Net; using System.Net.Http; using System.Net.Mail;namespace IdentityProject.Service {public class EmailSender : IEmailSender{private readonly EmailSettings _emailSettings;public EmailSender(IOptions<EmailSettings> emailSettings){_emailSettings = emailSettings.Value;}public async Task SendEmailAsync(string email, string subject, string htmlMessage){// 创建邮件对象var message = new MimeMessage();message.From.Add(new MailboxAddress("测试邮箱",//邮箱昵称_emailSettings.UserName));message.To.Add(MailboxAddress.Parse(email));message.Subject = subject;// 构建HTML正文var bodyBuilder = new BodyBuilder{HtmlBody = htmlMessage,TextBody = "您的邮件客户端不支持HTML显示"};message.Body = bodyBuilder.ToMessageBody();// 配置SMTP客户端using var client = new MailKit.Net.Smtp.SmtpClient();// 强制使用 TLS 1.2client.SslProtocols = System.Security.Authentication.SslProtocols.Tls12;await client.ConnectAsync(_emailSettings.SmtpServer,_emailSettings.Port,true);// 认证await client.AuthenticateAsync(_emailSettings.UserName,_emailSettings.Password);// 发送邮件await client.SendAsync(message);await client.DisconnectAsync(true);}} }
4)注册服务
- 代码如下(示例):
builder.Services.Configure<EmailSettings>(builder.Configuration.GetSection("EmailSettings")); builder.Services.AddScoped<IEmailSender, EmailSender>(); //调整令牌有效期(默认1天) builder.Services.Configure<DataProtectionTokenProviderOptions>(options => {options.TokenLifespan = TimeSpan.FromHours(2); // 设置为2小时 });
5)创建密码重置端点(控制器Controller)
- 示例代码AccountController.cs
using IdentityProject.Entity; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.UI.Services; using Microsoft.AspNetCore.Mvc; using System.Net;namespace IdentityProject.Controllers {[Route("api/[controller]/[action]")][ApiController]public class AccountController : ControllerBase{private readonly UserManager<ApplicationUser> _userManager;private readonly IEmailSender _emailSender;public AccountController(UserManager<ApplicationUser> userManager, IEmailSender emailSender){_userManager = userManager;_emailSender = emailSender;}/// <summary>/// 请求重置密码/// </summary>/// <param name="model"></param>/// <returns></returns>[HttpPost]public async Task<IActionResult> ForgotPassword([FromBody] ForgotPasswordRequest model){ var user=await _userManager.FindByEmailAsync(model.Email);var user1 = await _userManager.FindByNameAsync("LGF");if (user == null) return Ok();var token=await _userManager.GeneratePasswordResetTokenAsync(user);var resetLink= $"https://your@domain.com/reset-password?email={model.Email}&token={WebUtility.UrlEncode(token)}";await _emailSender.SendEmailAsync(model.Email, "重置密码", $"请点击链接重置密码:<a href='{resetLink}'>{resetLink}</a>");return Ok();}//设置新密码[HttpPost("reset-password")]public async Task<IActionResult> ResetPassword([FromBody] ResetPasswordRequest model){ApplicationUser user = await _userManager.FindByEmailAsync(model.Email);if (user == null) return BadRequest("用户不存在");var result = await _userManager.ResetPasswordAsync(user, model.Token, model.NewPassword);return result.Succeeded ? Ok() : BadRequest(result.Errors);}} }
namespace IdentityProject.Entity {public class ForgotPasswordRequest{public string Email { get; set; }} }
namespace IdentityProject.Entity {public class ResetPasswordRequest{public string Email { get; set; }public string Token { get; set; }public string NewPassword { get; set; }} }
三、关键注意事项
1)授权码获取
- 登录163邮箱→POP3/SMTP/IMAP→开启服务(IMAP/SMTP服务)→授权密码管理→新增授权密码
2)端口选择
端口 | 加密方式 | MailKit 参数 |
---|---|---|
465 | SSL | useSsl: true |
587 | TLS | useSsl: true |
3)编码问题
- 如果遇到乱码,强制指定编码
// 如果遇到乱码,强制指定编码 message.SubjectEncoding = Encoding.UTF8; bodyBuilder.HtmlBody = WebUtility.HtmlEncode(htmlMessage);
4)异常处理
- 参考代码
catch (AuthenticationException ex) {Console.WriteLine($"认证失败: {ex.Message}"); } catch (SmtpCommandException ex) {Console.WriteLine($"SMTP错误 (状态码: {ex.StatusCode}): {ex.Message}"); } catch (IOException ex) {Console.WriteLine($"网络错误: {ex.Message}"); }
四、常见问题排查
- 问题 1:超时无法连接
增加超时设置client.Timeout = 30000; // 30秒
- 问题 2:证书验证失败
跳过证书验证(仅测试环境使用)client.ServerCertificateValidationCallback = (s, c, h, e) => true;
- 邮件被识别为垃圾邮件
在邮件头中添加 X-Mailer 标识message.Headers.Add("X-Mailer", "MyApp Mail System");
总结
通过以上步骤,可实现密码重置功能