You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

79 lines
3.1 KiB

using MediatR;
using CellularManagement.Domain.Services;
using CellularManagement.Application.Common;
using System.Text;
using CellularManagement.Domain.Common;
using Microsoft.Extensions.Caching.Memory;
namespace CellularManagement.Application.Features.Auth.Commands.GenerateCaptcha;
public class GenerateCaptchaCommandHandler : IRequestHandler<GenerateCaptchaCommand, OperationResult<GenerateCaptchaResponse>>
{
private readonly ICaptchaService _captchaService;
private readonly ICacheService _cacheService;
private const string RATE_LIMIT_KEY_PREFIX = "captcha_rate_limit:";
private const int MAX_REQUESTS_PER_MINUTE = 30;
public GenerateCaptchaCommandHandler(
ICaptchaService captchaService,
ICacheService cacheService)
{
_captchaService = captchaService;
_cacheService = cacheService;
}
public async Task<OperationResult<GenerateCaptchaResponse>> Handle(
GenerateCaptchaCommand request,
CancellationToken cancellationToken)
{
try
{
// 获取客户端IP或标识
var clientId = request.ClientId ?? "anonymous";
var rateLimitKey = $"{RATE_LIMIT_KEY_PREFIX}{clientId}";
// 检查请求频率
var requestCount = _cacheService.Get<int>(rateLimitKey);
if (requestCount >= MAX_REQUESTS_PER_MINUTE)
{
var remainingTime = _cacheService.Get<DateTime>($"{rateLimitKey}:expiry");
var seconds = remainingTime != default
? (int)(remainingTime - DateTime.UtcNow).TotalSeconds
: 60;
return OperationResult<GenerateCaptchaResponse>.CreateFailure(
$"请求过于频繁,请{seconds}秒后再试");
}
// 更新请求计数
var rateLimitOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(1));
_cacheService.Set(rateLimitKey, requestCount + 1, rateLimitOptions);
_cacheService.Set($"{rateLimitKey}:expiry", DateTime.UtcNow.AddMinutes(1), rateLimitOptions);
// 生成验证码
var (code, imageBytes) = _captchaService.GenerateCaptcha(request.Length);
// 生成唯一ID
var captchaId = Guid.NewGuid().ToString();
// 将验证码存入缓存,设置5分钟过期
var cacheOptions = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(5));
_cacheService.Set($"captcha:{captchaId}", code, cacheOptions);
// 将图片转换为Base64
var base64Image = Convert.ToBase64String(imageBytes);
return await Task.FromResult(OperationResult<GenerateCaptchaResponse>.CreateSuccess(new GenerateCaptchaResponse
{
CaptchaId = captchaId,
ImageBase64 = base64Image
}));
}
catch (Exception ex)
{
return await Task.FromResult(OperationResult<GenerateCaptchaResponse>.CreateFailure("生成验证码失败"));
}
}
}