57 changed files with 496 additions and 13 deletions
@ -1,9 +1,10 @@ |
|||
using Microsoft.Extensions.Caching.Memory; |
|||
|
|||
namespace CellularManagement.Application.Services; |
|||
namespace CellularManagement.Domain.Services; |
|||
|
|||
/// <summary>
|
|||
/// 缓存服务接口
|
|||
/// 定义缓存操作的核心业务逻辑
|
|||
/// </summary>
|
|||
public interface ICacheService |
|||
{ |
@ -0,0 +1,33 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CellularManagement.Domain.Services; |
|||
|
|||
/// <summary>
|
|||
/// 邮箱服务接口
|
|||
/// 定义发送邮件和验证邮箱的基本功能
|
|||
/// </summary>
|
|||
public interface IEmailService |
|||
{ |
|||
/// <summary>
|
|||
/// 发送验证码邮件
|
|||
/// </summary>
|
|||
/// <param name="to">收件人邮箱</param>
|
|||
/// <param name="verificationCode">验证码</param>
|
|||
/// <returns>发送结果</returns>
|
|||
Task<bool> SendVerificationCodeAsync(string to, string verificationCode); |
|||
|
|||
/// <summary>
|
|||
/// 发送注册成功邮件
|
|||
/// </summary>
|
|||
/// <param name="to">收件人邮箱</param>
|
|||
/// <param name="username">用户名</param>
|
|||
/// <returns>发送结果</returns>
|
|||
Task<bool> SendRegistrationSuccessAsync(string to, string username); |
|||
|
|||
/// <summary>
|
|||
/// 验证邮箱格式
|
|||
/// </summary>
|
|||
/// <param name="email">邮箱地址</param>
|
|||
/// <returns>验证结果</returns>
|
|||
bool ValidateEmail(string email); |
|||
} |
@ -0,0 +1,25 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CellularManagement.Domain.Services; |
|||
|
|||
/// <summary>
|
|||
/// 邮箱验证码服务接口
|
|||
/// 定义验证码生成、发送和验证的核心业务逻辑
|
|||
/// </summary>
|
|||
public interface IEmailVerificationService |
|||
{ |
|||
/// <summary>
|
|||
/// 生成并发送验证码
|
|||
/// </summary>
|
|||
/// <param name="email">邮箱地址</param>
|
|||
/// <returns>是否发送成功</returns>
|
|||
Task<bool> GenerateAndSendVerificationCodeAsync(string email); |
|||
|
|||
/// <summary>
|
|||
/// 验证验证码
|
|||
/// </summary>
|
|||
/// <param name="email">邮箱地址</param>
|
|||
/// <param name="code">验证码</param>
|
|||
/// <returns>验证结果</returns>
|
|||
Task<bool> VerifyCodeAsync(string email, string code); |
|||
} |
@ -1,6 +1,7 @@ |
|||
using System.Collections.Generic; |
|||
using System.Security.Claims; |
|||
|
|||
namespace CellularManagement.Application.Services; |
|||
namespace CellularManagement.Domain.Services; |
|||
|
|||
/// <summary>
|
|||
/// JWT 令牌提供者接口
|
@ -1,9 +1,10 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace CellularManagement.Application.Services; |
|||
namespace CellularManagement.Domain.Services; |
|||
|
|||
/// <summary>
|
|||
/// 密钥轮换服务接口
|
|||
/// 定义密钥轮换的核心业务逻辑
|
|||
/// </summary>
|
|||
public interface IKeyRotationService |
|||
{ |
@ -0,0 +1,42 @@ |
|||
namespace CellularManagement.Infrastructure.Options; |
|||
|
|||
/// <summary>
|
|||
/// 邮箱配置选项
|
|||
/// </summary>
|
|||
public class EmailOptions |
|||
{ |
|||
/// <summary>
|
|||
/// 配置节点名称
|
|||
/// </summary>
|
|||
public const string SectionName = "Email"; |
|||
|
|||
/// <summary>
|
|||
/// SMTP服务器地址
|
|||
/// </summary>
|
|||
public string SmtpServer { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// SMTP服务器端口
|
|||
/// </summary>
|
|||
public int SmtpPort { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// 发件人邮箱地址
|
|||
/// </summary>
|
|||
public string FromEmail { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 发件人显示名称
|
|||
/// </summary>
|
|||
public string FromName { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 邮箱密码或授权码
|
|||
/// </summary>
|
|||
public string Password { get; set; } = string.Empty; |
|||
|
|||
/// <summary>
|
|||
/// 是否启用SSL
|
|||
/// </summary>
|
|||
public bool EnableSsl { get; set; } |
|||
} |
@ -0,0 +1,116 @@ |
|||
using System; |
|||
using System.Text.RegularExpressions; |
|||
using System.Threading.Tasks; |
|||
using CellularManagement.Domain.Services; |
|||
using CellularManagement.Infrastructure.Options; |
|||
using MailKit.Net.Smtp; |
|||
using MailKit.Security; |
|||
using Microsoft.Extensions.Options; |
|||
using MimeKit; |
|||
|
|||
namespace CellularManagement.Infrastructure.Services; |
|||
|
|||
/// <summary>
|
|||
/// 邮箱服务实现类
|
|||
/// </summary>
|
|||
public class EmailService : IEmailService |
|||
{ |
|||
private readonly EmailOptions _emailOptions; |
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
/// <param name="emailOptions">邮箱配置选项</param>
|
|||
public EmailService(IOptions<EmailOptions> emailOptions) |
|||
{ |
|||
_emailOptions = emailOptions.Value; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送验证码邮件
|
|||
/// </summary>
|
|||
public async Task<bool> SendVerificationCodeAsync(string to, string verificationCode) |
|||
{ |
|||
try |
|||
{ |
|||
var message = new MimeMessage(); |
|||
message.From.Add(new MailboxAddress(_emailOptions.FromName, _emailOptions.FromEmail)); |
|||
message.To.Add(new MailboxAddress("", to)); |
|||
message.Subject = "邮箱验证码"; |
|||
|
|||
var bodyBuilder = new BodyBuilder |
|||
{ |
|||
HtmlBody = $@"
|
|||
<h2>您的验证码</h2> |
|||
<p>您的验证码是:<strong>{verificationCode}</strong></p> |
|||
<p>验证码有效期为5分钟,请尽快使用。</p> |
|||
<p>如果这不是您的操作,请忽略此邮件。</p>"
|
|||
}; |
|||
|
|||
message.Body = bodyBuilder.ToMessageBody(); |
|||
|
|||
using var client = new SmtpClient(); |
|||
await client.ConnectAsync(_emailOptions.SmtpServer, _emailOptions.SmtpPort, _emailOptions.EnableSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.StartTls); |
|||
await client.AuthenticateAsync(_emailOptions.FromEmail, _emailOptions.Password); |
|||
await client.SendAsync(message); |
|||
await client.DisconnectAsync(true); |
|||
|
|||
return true; |
|||
} |
|||
catch (Exception) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 发送注册成功邮件
|
|||
/// </summary>
|
|||
public async Task<bool> SendRegistrationSuccessAsync(string to, string username) |
|||
{ |
|||
try |
|||
{ |
|||
var message = new MimeMessage(); |
|||
message.From.Add(new MailboxAddress(_emailOptions.FromName, _emailOptions.FromEmail)); |
|||
message.To.Add(new MailboxAddress(username, to)); |
|||
message.Subject = "注册成功通知"; |
|||
|
|||
var bodyBuilder = new BodyBuilder |
|||
{ |
|||
HtmlBody = $@"
|
|||
<h2>注册成功</h2> |
|||
<p>尊敬的 {username}:</p> |
|||
<p>恭喜您成功注册我们的服务!</p> |
|||
<p>您现在可以使用注册的邮箱和密码登录系统。</p> |
|||
<p>如有任何问题,请随时联系我们。</p>"
|
|||
}; |
|||
|
|||
message.Body = bodyBuilder.ToMessageBody(); |
|||
|
|||
using var client = new SmtpClient(); |
|||
await client.ConnectAsync(_emailOptions.SmtpServer, _emailOptions.SmtpPort, _emailOptions.EnableSsl ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.StartTls); |
|||
await client.AuthenticateAsync(_emailOptions.FromEmail, _emailOptions.Password); |
|||
await client.SendAsync(message); |
|||
await client.DisconnectAsync(true); |
|||
|
|||
return true; |
|||
} |
|||
catch (Exception) |
|||
{ |
|||
return false; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 验证邮箱格式
|
|||
/// </summary>
|
|||
public bool ValidateEmail(string email) |
|||
{ |
|||
if (string.IsNullOrWhiteSpace(email)) |
|||
return false; |
|||
|
|||
// 使用正则表达式验证邮箱格式
|
|||
const string pattern = @"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$"; |
|||
return Regex.IsMatch(email, pattern); |
|||
} |
|||
} |
@ -0,0 +1,132 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using CellularManagement.Domain.Services; |
|||
using Microsoft.Extensions.Caching.Distributed; |
|||
using System.Text.Json; |
|||
|
|||
namespace CellularManagement.Infrastructure.Services; |
|||
|
|||
/// <summary>
|
|||
/// 邮箱验证码服务
|
|||
/// 提供验证码生成、发送和验证的具体实现
|
|||
/// </summary>
|
|||
public class EmailVerificationService : IEmailVerificationService |
|||
{ |
|||
private readonly IEmailService _emailService; |
|||
private readonly IDistributedCache _cache; |
|||
private const string CacheKeyPrefix = "EmailVerification_"; |
|||
private const int VerificationCodeLength = 6; |
|||
private const int VerificationCodeExpirationMinutes = 5; |
|||
|
|||
/// <summary>
|
|||
/// 构造函数
|
|||
/// </summary>
|
|||
/// <param name="emailService">邮箱服务</param>
|
|||
/// <param name="cache">分布式缓存</param>
|
|||
public EmailVerificationService(IEmailService emailService, IDistributedCache cache) |
|||
{ |
|||
_emailService = emailService; |
|||
_cache = cache; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 生成并发送验证码
|
|||
/// </summary>
|
|||
/// <param name="email">邮箱地址</param>
|
|||
/// <returns>是否发送成功</returns>
|
|||
public async Task<bool> GenerateAndSendVerificationCodeAsync(string email) |
|||
{ |
|||
if (!_emailService.ValidateEmail(email)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// 生成6位数字验证码
|
|||
var verificationCode = GenerateVerificationCode(); |
|||
|
|||
// 将验证码保存到缓存
|
|||
var cacheKey = $"{CacheKeyPrefix}{email}"; |
|||
var cacheValue = JsonSerializer.Serialize(new |
|||
{ |
|||
Code = verificationCode, |
|||
CreatedAt = DateTime.UtcNow |
|||
}); |
|||
|
|||
await _cache.SetStringAsync( |
|||
cacheKey, |
|||
cacheValue, |
|||
new DistributedCacheEntryOptions |
|||
{ |
|||
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(VerificationCodeExpirationMinutes) |
|||
}); |
|||
|
|||
// 发送验证码邮件
|
|||
return await _emailService.SendVerificationCodeAsync(email, verificationCode); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 验证验证码
|
|||
/// </summary>
|
|||
/// <param name="email">邮箱地址</param>
|
|||
/// <param name="code">验证码</param>
|
|||
/// <returns>验证结果</returns>
|
|||
public async Task<bool> VerifyCodeAsync(string email, string code) |
|||
{ |
|||
var cacheKey = $"{CacheKeyPrefix}{email}"; |
|||
var cachedValue = await _cache.GetStringAsync(cacheKey); |
|||
|
|||
if (string.IsNullOrEmpty(cachedValue)) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
var verificationData = JsonSerializer.Deserialize<VerificationData>(cachedValue); |
|||
|
|||
if (verificationData == null) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// 验证码是否过期
|
|||
if (DateTime.UtcNow - verificationData.CreatedAt > TimeSpan.FromMinutes(VerificationCodeExpirationMinutes)) |
|||
{ |
|||
await _cache.RemoveAsync(cacheKey); |
|||
return false; |
|||
} |
|||
|
|||
// 验证码是否匹配
|
|||
if (verificationData.Code != code) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// 验证成功后删除缓存
|
|||
await _cache.RemoveAsync(cacheKey); |
|||
return true; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 生成验证码
|
|||
/// </summary>
|
|||
private string GenerateVerificationCode() |
|||
{ |
|||
var random = new Random(); |
|||
var code = string.Empty; |
|||
|
|||
for (int i = 0; i < VerificationCodeLength; i++) |
|||
{ |
|||
code += random.Next(0, 10).ToString(); |
|||
} |
|||
|
|||
return code; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// 验证数据
|
|||
/// </summary>
|
|||
private class VerificationData |
|||
{ |
|||
public string Code { get; set; } = string.Empty; |
|||
public DateTime CreatedAt { get; set; } |
|||
} |
|||
} |
@ -0,0 +1,17 @@ |
|||
{ |
|||
"Logging": { |
|||
"LogLevel": { |
|||
"Default": "Information", |
|||
"Microsoft.AspNetCore": "Warning" |
|||
} |
|||
}, |
|||
"AllowedHosts": "*", |
|||
"Email": { |
|||
"SmtpServer": "smtp.example.com", |
|||
"SmtpPort": 587, |
|||
"FromEmail": "noreply@example.com", |
|||
"FromName": "系统通知", |
|||
"Password": "your-email-password", |
|||
"EnableSsl": true |
|||
} |
|||
} |
Loading…
Reference in new issue