文章目录
前言
密码重置功能
一、密码重置流程原理
- 核心步骤:
- 用户请求重置密码(提供注册邮箱/用户名)
- 系统生成密码重置令牌并发送到用户邮箱
- 用户点击邮件中的链接,进入密码重置页面
- 提交新密码和令牌,系统验证并更新密码
- 关键技术:
- 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.2 client.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");
总结
通过以上步骤,可实现密码重置功能