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>();
|
app.UseMiddleware<GlobalExceptionMiddleware>();
|
||||||
|
|
||||||
|
// 请求限流中间件:限制用户请求频率,保护第三方API配额
|
||||||
|
app.UseMiddleware<RateLimitMiddleware>();
|
||||||
|
|
||||||
if (app.Environment.IsDevelopment())
|
if (app.Environment.IsDevelopment())
|
||||||
{
|
{
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user