P0 实现请求限流中间件:每分钟60次请求限制,保护第三方API配额
This commit is contained in:
parent
89244fc078
commit
e5cf289da1
68
AssetManager.API/Middleware/RateLimitMiddleware.cs
Normal file
68
AssetManager.API/Middleware/RateLimitMiddleware.cs
Normal file
@ -0,0 +1,68 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace AssetManager.API.Middleware;
|
||||
|
||||
/// <summary>
|
||||
/// 请求限流中间件:限制每个用户的请求频率,保护第三方API配额
|
||||
/// </summary>
|
||||
public class RateLimitMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IMemoryCache _cache;
|
||||
private readonly ILogger<RateLimitMiddleware> _logger;
|
||||
|
||||
// 限流配置:每个用户每分钟最多请求60次(平均1秒1次,足够正常使用)
|
||||
private const int Limit = 60;
|
||||
private const int WindowSeconds = 60;
|
||||
private const string CacheKeyPrefix = "RateLimit_";
|
||||
|
||||
public RateLimitMiddleware(RequestDelegate next, IMemoryCache cache, ILogger<RateLimitMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_cache = cache;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
// 获取用户ID(未登录则用IP地址)
|
||||
var userId = context.User.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value
|
||||
?? context.Connection.RemoteIpAddress?.ToString()
|
||||
?? "anonymous";
|
||||
|
||||
var cacheKey = $"{CacheKeyPrefix}{userId}";
|
||||
|
||||
// 获取当前窗口的请求计数
|
||||
var requestCount = _cache.Get<int>(cacheKey);
|
||||
|
||||
if (requestCount >= Limit)
|
||||
{
|
||||
_logger.LogWarning("用户 {UserId} 请求超过限流限制,当前计数: {Count}", userId, requestCount);
|
||||
context.Response.StatusCode = StatusCodes.Status429TooManyRequests;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync(System.Text.Json.JsonSerializer.Serialize(new
|
||||
{
|
||||
code = 429,
|
||||
message = "请求过于频繁,请稍后再试",
|
||||
data = (object)null
|
||||
}));
|
||||
return;
|
||||
}
|
||||
|
||||
// 计数+1,首次访问设置过期时间
|
||||
if (requestCount == 0)
|
||||
{
|
||||
_cache.Set(cacheKey, 1, TimeSpan.FromSeconds(WindowSeconds));
|
||||
}
|
||||
else
|
||||
{
|
||||
_cache.Set(cacheKey, requestCount + 1, _cache.GetEntry(cacheKey).AbsoluteExpirationRelativeToNow ?? TimeSpan.FromSeconds(WindowSeconds));
|
||||
}
|
||||
|
||||
await _next(context);
|
||||
}
|
||||
}
|
||||
@ -118,6 +118,9 @@ app.Services.InitializeDatabase();
|
||||
// 全局异常处理中间件(必须放在最前面)
|
||||
app.UseMiddleware<GlobalExceptionMiddleware>();
|
||||
|
||||
// 请求限流中间件:限制用户请求频率,保护第三方API配额
|
||||
app.UseMiddleware<RateLimitMiddleware>();
|
||||
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user