I have to implement rate limiting to public endpoints using .Net 7 new Rate limiting Middleware.
For now I've settled on a fixedWindow rate limiter.
I've found many differents implementations online, but the only ones I found implementing any kind of filtering on IP/Client are using the globalLimiter which I dont want.
I have many endpoints and I want 2 different limiters on 2 of my public endpoints.
What I want is a mix of the 2 following implementation, which allows me to name the policy to implement it on only the endpoints, and the rate limiting to be per/client.
2 different policies I can assign to each of my endpoints:
builder.Services.AddRateLimiter(options =>
{
options.AddFixedWindowLimiter("myRateLimiter1", options =>
{
options.AutoReplenishment = true;
options.PermitLimit = 1;
options.Window = TimeSpan.FromSeconds(30);
});
options.AddFixedWindowLimiter("myRateLimiter12", options =>
{
options.AutoReplenishment = true;
options.PermitLimit = 1;
options.Window = TimeSpan.FromSeconds(30);
});
});
Filtering clients that is implemented globally
builder.Services.AddRateLimiter(options =>
{
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
RateLimitPartition.GetFixedWindowLimiter(
partitionKey: httpContext.User.Identity?.Name ?? httpContext.Request.Headers.Host.ToString(),
factory: partition => new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 1,
QueueLimit = 0,
Window = TimeSpan.FromSeconds(30)
}));
});
I also found this implementation that does the job but cant find how to add filtering either
app.UseRateLimiter(new RateLimiterOptions
{
OnRejected = (context, _) =>
{
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
context.HttpContext.Response.Headers.RetryAfter =
((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
app.Logger.LogWarning("Rate limit exceeded, retry after {RetryAfter} seconds", retryAfter.TotalSeconds);
}
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
return new ValueTask();
}
}
.AddFixedWindowLimiter("myRateLimiter1", options =>
{
options.AutoReplenishment = true;
options.PermitLimit = 1;
options.Window = TimeSpan.FromSeconds(10);
options.QueueLimit = 0;
}).AddFixedWindowLimiter("myRateLimiter2", options =>
{
options.AutoReplenishment = true;
options.PermitLimit = 1;
options.Window = TimeSpan.FromSeconds(10);
options.QueueLimit = 0;
}));
CodePudding user response:
Add your limiters via RateLimiterOptions.AddPolicy
:
builder.Services.AddRateLimiter(options =>
{
options.AddPolicy("myRateLimiter1", context => RateLimitPartition.GetFixedWindowLimiter(
partitionKey: context.User.Identity?.Name ?? context.Request.Headers.Host.ToString(),
factory: partition => new FixedWindowRateLimiterOptions
{
AutoReplenishment = true,
PermitLimit = 1,
QueueLimit = 0,
Window = TimeSpan.FromSeconds(30)
}));
// and the second one
});