Files
myAi/startup-helpers/RateLimitingExtensions.cs
T
2026-05-12 09:56:43 +03:00

76 lines
3.1 KiB
C#

using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Shared.Models.Settings;
namespace StartupHelpers;
public static class RateLimitingExtensions
{
public static void AddPublicApiRateLimiting(
this IServiceCollection services,
IConfiguration configuration,
string sectionName = "RateLimiting")
{
var settings = configuration.GetSection(sectionName).Get<RateLimitingSettings>()
?? new RateLimitingSettings();
services.AddRateLimiter(options =>
{
var global = settings.Global ?? new RateLimitPolicySettings();
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{
var ip = httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
return RateLimitPartition.GetFixedWindowLimiter(
partitionKey: ip,
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = global.PermitLimit,
Window = global.Window,
QueueLimit = global.QueueLimit,
AutoReplenishment = global.AutoReplenishment
});
});
foreach (var entry in settings.Policies)
{
var policyName = entry.Key;
var policy = entry.Value ?? new RateLimitPolicySettings();
options.AddPolicy(policyName, httpContext =>
{
var ip = httpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
return RateLimitPartition.GetFixedWindowLimiter(
partitionKey: ip,
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = policy.PermitLimit,
Window = policy.Window,
QueueLimit = policy.QueueLimit,
AutoReplenishment = policy.AutoReplenishment
});
});
}
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
options.OnRejected = async (context, ct) =>
{
var logger = context.HttpContext.RequestServices
.GetRequiredService<ILoggerFactory>()
.CreateLogger("RateLimiting");
var ip = context.HttpContext.Connection.RemoteIpAddress?.ToString() ?? "unknown";
var endpoint = context.HttpContext.Request.Path;
logger.LogWarning("Rate limit exceeded for {Endpoint} from IP {IP}", endpoint, ip);
context.HttpContext.Response.ContentType = "application/json";
await context.HttpContext.Response.WriteAsync("""{"error":"Too many requests. Try again later."}""", ct);
};
});
}
}