<develop>:(ShopERP 端)<无> 找回密码,增加 发送邮件的功能。

parent 814c17bb
......@@ -107,6 +107,10 @@
/// </summary>
public const string SetDataFailure = "设置数据失败!";
public const string SendEmailSuccess = "发送邮件成功!";
public const string SendEmailFailure = "发送邮件失败!";
//缓存数据
/// <summary>
/// 缓存已经排序后台导航
......
......@@ -131,4 +131,18 @@ namespace CoreCms.Net.Model.FromBody
/// </summary>
public string propsDate { get; set; }
}
/// <summary>
/// API 发送验证码-忘记密码
/// </summary>
public class FMSendValidCodeForgetPasswordPost
{
public string userName { get; set; }
public string userEmail { get; set; }
}
}
\ No newline at end of file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace CoreCms.Net.Model.ViewModels.Email
{
public class MailConfiguration
{
public string SmtpServer { get; set; } = string.Empty;
public int SmtpPort { get; set; } = 587;
public string UserName { get; set; } = string.Empty;
public string Password { get; set; } = string.Empty;
public string DisplayName { get; set; } = "System Notification";
public bool EnableSsl { get; set; } = true;
public string FromAddress { get; set; } = string.Empty;
public int Timeout { get; set; } = 10000; // 10 seconds
public bool UseDefaultCredentials { get; set; } = false;
}
/// <summary>
/// 邮箱要添加的附件
/// </summary>
public class MailAttachment
{
public byte[]? FileData { get; set; }
public string? FileName { get; set; }
public string? MediaType { get; set; } // e.g., MediaTypeNames.Application.Pdf
}
public class MailMessageModel
{
public List<string> ToAddresses { get; set; } = new List<string>();
public List<string>? CcAddresses { get; set; }
public List<string>? BccAddresses { get; set; }
public string? Subject { get; set; }
public string? Body { get; set; }
public bool IsBodyHtml { get; set; } = true;
public List<MailAttachment>? Attachments { get; set; }
public Encoding? Encoding { get; set; } = Encoding.UTF8;
}
}
using CoreCms.Net.Model.ViewModels.Email;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Text;
using System.Threading.Tasks;
namespace CoreCms.Net.Utility.Helper
{
public class EmailSenderHelper
{
private readonly MailConfiguration _config;
private readonly ILogger<EmailSenderHelper>? _logger;
public EmailSenderHelper(MailConfiguration config, ILogger<EmailSenderHelper>? logger = null)
{
_config = config;
_logger = logger;
ValidateConfiguration();
}
private void ValidateConfiguration()
{
if (string.IsNullOrWhiteSpace(_config.SmtpServer))
throw new ArgumentNullException(nameof(_config.SmtpServer));
if (string.IsNullOrWhiteSpace(_config.UserName))
throw new ArgumentNullException(nameof(_config.UserName));
if (string.IsNullOrWhiteSpace(_config.Password))
throw new ArgumentNullException(nameof(_config.Password));
}
public async Task SendEmailAsync(MailMessageModel message)
{
if (message == null)
throw new ArgumentNullException(nameof(message));
if (!message.ToAddresses.Any())
throw new InvalidOperationException("No recipients specified");
using var smtpClient = CreateSmtpClient();
using var mailMessage = CreateMailMessage(message);
try
{
await smtpClient.SendMailAsync(mailMessage);
_logger?.LogInformation($"Email sent to {string.Join(", ", message.ToAddresses)}");
}
catch (SmtpException ex)
{
_logger?.LogError(ex, $"SMTP error sending email: {ex.Message}");
throw; // Rethrow to allow caller handling
}
catch (Exception ex)
{
_logger?.LogError(ex, $"Error sending email: {ex.Message}");
throw;
}
}
private SmtpClient CreateSmtpClient()
{
return new SmtpClient(_config.SmtpServer, _config.SmtpPort)
{
EnableSsl = _config.EnableSsl,
Credentials = new NetworkCredential(_config.UserName, _config.Password),
DeliveryMethod = SmtpDeliveryMethod.Network,
Timeout = _config.Timeout,
UseDefaultCredentials = _config.UseDefaultCredentials
};
}
private MailMessage CreateMailMessage(MailMessageModel model)
{
var fromAddress = string.IsNullOrWhiteSpace(_config.FromAddress)
? _config.UserName
: _config.FromAddress;
var mail = new MailMessage
{
From = new MailAddress(fromAddress, _config.DisplayName),
Subject = model.Subject ?? "[No Subject]",
Body = model.Body ?? string.Empty,
IsBodyHtml = model.IsBodyHtml,
BodyEncoding = model.Encoding ?? Encoding.UTF8,
SubjectEncoding = model.Encoding ?? Encoding.UTF8
};
// Add recipients
model.ToAddresses.ForEach(to => mail.To.Add(to));
model.CcAddresses?.ForEach(cc => mail.CC.Add(cc));
model.BccAddresses?.ForEach(bcc => mail.Bcc.Add(bcc));
// Add attachments
if (model.Attachments != null)
{
foreach (var attachment in model.Attachments)
{
if (attachment.FileData == null || string.IsNullOrWhiteSpace(attachment.FileName))
continue;
var stream = new MemoryStream(attachment.FileData);
mail.Attachments.Add(new Attachment(
stream,
attachment.FileName,
attachment.MediaType ?? MediaTypeNames.Application.Octet
));
}
}
return mail;
}
}
}
......@@ -14,6 +14,7 @@ using CoreCms.Net.IServices;
using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.FromBody;
using CoreCms.Net.Model.ViewModels.DTO.UserInfo;
using CoreCms.Net.Model.ViewModels.Email;
using CoreCms.Net.Model.ViewModels.UI;
using CoreCms.Net.Services;
using CoreCms.Net.Utility.Extensions;
......@@ -41,6 +42,7 @@ namespace CoreCms.Net.Web.Admin.Controllers
private readonly ISysRoleMenuServices _sysRoleMenuServices;
private readonly ISysLoginRecordRepository _sysLoginRecordRepository;
private readonly ICoreCmsUserServices _coreCmsUserServices;
private readonly EmailSenderHelper _emailSender;//发邮件的服务
#region 构造函数注入
/// <summary>
......@@ -53,6 +55,7 @@ namespace CoreCms.Net.Web.Admin.Controllers
, ISysRoleMenuServices sysRoleMenuServices
, IHttpContextAccessor httpContextAccessor
, ISysLoginRecordRepository sysLoginRecordRepository
, EmailSenderHelper emailSender
)
{
_permissionRequirement = permissionRequirement;
......@@ -61,6 +64,7 @@ namespace CoreCms.Net.Web.Admin.Controllers
_httpContextAccessor = httpContextAccessor;
_sysLoginRecordRepository = sysLoginRecordRepository;
_coreCmsUserServices = coreCmsUserServices;
_emailSender = emailSender;
}
#endregion
......@@ -285,5 +289,89 @@ namespace CoreCms.Net.Web.Admin.Controllers
#endregion
#region 忘记密码-发送验证码
/// <summary>
/// POST: api/login/DoSendValidCode
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
[HttpPost]
[Description("发送验证码修改密码")]
public async Task<AdminUiCallBack> DoSendValidCode([FromBody] FMSendValidCodeForgetPasswordPost param)
{
var jm = new AdminUiCallBack();
if (string.IsNullOrEmpty(param.userEmail))
{
jm.msg = "请输入用户邮箱!";
return jm;
}
var user = await _sysUserServices.QueryByClauseAsync(p => p.userName == param.userName && p.email == param.userEmail);
if (user != null)
{
if (user.state == 1)
{
jm.msg = "您的账户已经被冻结,请联系管理员解锁";
return jm;
}
//发送验证码, 发送邮件
Random rd = new Random();
int codeNumber = rd.Next(100000, 999999);
SendVerificationEmailAsync(param.userEmail, codeNumber.ToString());
var bl = true;
jm.code = bl ? 0 : 1;
jm.msg = bl ? GlobalConstVars.SendEmailSuccess : GlobalConstVars.SendEmailFailure;
return jm;
}
else
{
jm.msg = "您输入的用户与邮箱不匹配!";
return jm;
}
}
/// <summary>
/// 异步发送验证码
/// </summary>
/// <param name="email"></param>
/// <param name="verificationCode"></param>
public async void SendVerificationEmailAsync(string email, string verificationCode)
{
var message = new MailMessageModel()
{
ToAddresses = new List<string> { email },
Subject = "邮箱验证码",
Body = $"""
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>邮箱验证</title>
</head>
<body>
<div style="max-width: 600px; margin: 0 auto; font-family: Arial, sans-serif;">
<h2 style="color: #1e9fff;">邮箱验证请求</h2>
<p>您的验证码是:<strong style="font-size: 24px; letter-spacing: 2px;">
{verificationCode}
</strong></p>
<p>验证码将在30分钟后失效,请尽快使用。</p>
<hr style="border: 0; border-top: 1px solid #eee;">
<p style="color: #999; font-size: 12px;">此为系统邮件,请勿直接回复</p>
</div>
</body>
</html>
""",
IsBodyHtml = true
};
await _emailSender.SendEmailAsync(message);
}
#endregion
}
}
......@@ -530,7 +530,7 @@
用户授权登录
</summary>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.#ctor(CoreCms.Net.Auth.Policys.PermissionRequirement,CoreCms.Net.IServices.ICoreCmsUserServices,CoreCms.Net.IServices.ISysUserServices,CoreCms.Net.IServices.ISysRoleMenuServices,Microsoft.AspNetCore.Http.IHttpContextAccessor,CoreCms.Net.IRepository.ISysLoginRecordRepository)">
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.#ctor(CoreCms.Net.Auth.Policys.PermissionRequirement,CoreCms.Net.IServices.ICoreCmsUserServices,CoreCms.Net.IServices.ISysUserServices,CoreCms.Net.IServices.ISysRoleMenuServices,Microsoft.AspNetCore.Http.IHttpContextAccessor,CoreCms.Net.IRepository.ISysLoginRecordRepository,CoreCms.Net.Utility.Helper.EmailSenderHelper)">
<summary>
构造函数注入
</summary>
......@@ -556,6 +556,20 @@
<param name="param"></param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.DoSendValidCode(CoreCms.Net.Model.FromBody.FMSendValidCodeForgetPasswordPost)">
<summary>
POST: api/login/DoSendValidCode
</summary>
<param name="param"></param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.SendVerificationEmailAsync(System.String,System.String)">
<summary>
异步发送验证码
</summary>
<param name="email"></param>
<param name="verificationCode"></param>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.ToolsController">
<summary>
后端常用方法
......
......@@ -3,10 +3,13 @@ using CoreCms.Net.Configuration;
using CoreCms.Net.Core.Config;
using CoreCms.Net.Loging;
using CoreCms.Net.Mapping;
using CoreCms.Net.Model.ViewModels.Email;
using CoreCms.Net.Utility.Helper;
using Essensoft.Paylink.Alipay;
using Essensoft.Paylink.WeChatPay;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Newtonsoft.Json;
......@@ -30,6 +33,21 @@ namespace CoreCms.Net.Web.Admin.Infrastructure
builder.Services.AddSingleton(new AppSettingsHelper(builder.Environment.ContentRootPath));
builder.Services.AddSingleton(new LogLockHelper(builder.Environment.ContentRootPath));
// 从配置中读取邮件设置
var mailConfig = new MailConfiguration
{
SmtpServer = builder.Configuration["Smtp:Server"],
SmtpPort = builder.Configuration.GetValue<int>("Smtp:Port"),
UserName = builder.Configuration["Smtp:Username"],
Password = builder.Configuration["Smtp:Password"],
FromAddress = builder.Configuration["Smtp:FromAddress"],
DisplayName = builder.Configuration["Smtp:DisplayName"] ?? "My Application"
};
// 注册邮件服务
builder.Services.AddSingleton(mailConfig);
builder.Services.AddScoped<EmailSenderHelper>();
//Memory缓存
builder.Services.AddMemoryCacheSetup();
//Redis缓存
......
......@@ -5,6 +5,14 @@
"SqlConnection": "Server=192.168.8.109;Port=3306;Database=ShopERP;Uid=root;Pwd=123456;CharSet=utf8;pooling=true;SslMode=None;Allow User Variables=true;Convert Zero Datetime=True;Allow Zero Datetime=True;"
// Mysql数据库链接字符串,请保持后面的属性别少。经过测试,mysql版本需要5.7或以上
},
"Smtp": {
"Server": "smtp.exmail.qq.com",
"Port": 465,
"Username": "erpservice@geekbuy.com",
"Password": "co69W7xEZ6qjBo01",
"FromAddress": "erpservice@geekbuy.com",
"DisplayName": "My Application"
},
//定时任务管理面板的账户密码
"HangFire": {
"Login": "CoreShop",
......
......@@ -530,7 +530,7 @@
用户授权登录
</summary>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.#ctor(CoreCms.Net.Auth.Policys.PermissionRequirement,CoreCms.Net.IServices.ICoreCmsUserServices,CoreCms.Net.IServices.ISysUserServices,CoreCms.Net.IServices.ISysRoleMenuServices,Microsoft.AspNetCore.Http.IHttpContextAccessor,CoreCms.Net.IRepository.ISysLoginRecordRepository)">
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.#ctor(CoreCms.Net.Auth.Policys.PermissionRequirement,CoreCms.Net.IServices.ICoreCmsUserServices,CoreCms.Net.IServices.ISysUserServices,CoreCms.Net.IServices.ISysRoleMenuServices,Microsoft.AspNetCore.Http.IHttpContextAccessor,CoreCms.Net.IRepository.ISysLoginRecordRepository,CoreCms.Net.Utility.Helper.EmailSenderHelper)">
<summary>
构造函数注入
</summary>
......@@ -556,6 +556,20 @@
<param name="param"></param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.DoSendValidCode(CoreCms.Net.Model.FromBody.FMSendValidCodeForgetPasswordPost)">
<summary>
POST: api/login/DoSendValidCode
</summary>
<param name="param"></param>
<returns></returns>
</member>
<member name="M:CoreCms.Net.Web.Admin.Controllers.LoginController.SendVerificationEmailAsync(System.String,System.String)">
<summary>
异步发送验证码
</summary>
<param name="email"></param>
<param name="verificationCode"></param>
</member>
<member name="T:CoreCms.Net.Web.Admin.Controllers.ToolsController">
<summary>
后端常用方法
......
......@@ -5,6 +5,14 @@
"SqlConnection": "Server=192.168.8.109;Port=3306;Database=ShopERP;Uid=root;Pwd=123456;CharSet=utf8;pooling=true;SslMode=None;Allow User Variables=true;Convert Zero Datetime=True;Allow Zero Datetime=True;"
// Mysql数据库链接字符串,请保持后面的属性别少。经过测试,mysql版本需要5.7或以上
},
"Smtp": {
"Server": "smtp.exmail.qq.com",
"Port": 465,
"Username": "erpservice@geekbuy.com",
"Password": "co69W7xEZ6qjBo01",
"FromAddress": "erpservice@geekbuy.com",
"DisplayName": "My Application"
},
//定时任务管理面板的账户密码
"HangFire": {
"Login": "CoreShop",
......
......@@ -84,20 +84,33 @@
$('#btnSendValidCode').on('click', function () {
layer.msg("哈哈哈哈");
//用户工号
var userName = $("#userName").val();
var strUserName = $("#userName").val();
//发送验证码功能
var userEmail = $("#email").val();
var strUserEmail = $("#email").val();
// 如果没有错误,则验证通过
var errorUserName = form.validate($("#userName"));
var errorEmail = form.validate($("#email"));
if (errorUserName || errorEmail) {
return; // 验证不通过,自动显示错误信息
}
layer.msg("22");
//// 如果没有错误,则验证通过
//var errorEmail = form.validate($("#email"));
//if (errorEmail) {
// return; // 验证不通过,自动显示错误信息
//}
layer.msg("-用户工号:" + userName + ",用户邮箱:" + userEmail);
layer.msg("33");
//提交 Ajax 到后台 (判断工号 与 邮箱是否匹配)
coreHelper.Post("api/login/DoSendValidCode", { userName: strUserName, userEmail: strUserEmail }, function (e) {
console.log(e)
if (e.code === 0) {
layer.msg(e.msg);
} else {
layer.msg(e.msg);
}
});
});
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment