#define JWT // FIRST ADMIN FIXED SLIDING CONCUR TOKEN FIXED2 JWT
#if NEVER
#elif FIXED
//
using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");
app.UseRateLimiter(new RateLimiterOptions()
.AddFixedWindowLimiter(policyName: "fixed",
options =>
{
options.PermitLimit = 4;
options.Window = TimeSpan.FromSeconds(12);
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = 2;
}));
app.MapGet("/", () => Results.Ok($"Hello {GetTicks()}"))
.RequireRateLimiting("fixed");
app.Run();
//
#elif FIXED2
//
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.RateLimiting;
using WebRateLimitAuth.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure(
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit));
var app = builder.Build();
static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");
var myOptions = new MyRateLimitOptions();
app.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
var fixedPolicy = "fixed";
app.UseRateLimiter(new RateLimiterOptions()
.AddFixedWindowLimiter(policyName: fixedPolicy,
options =>
{
options.PermitLimit = myOptions.permitLimit;
options.Window = TimeSpan.FromSeconds(myOptions.window);
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = myOptions.queueLimit;
}));
app.MapGet("/", () => Results.Ok($"Hello {GetTicks()}"))
.RequireRateLimiting(fixedPolicy);
app.Run();
//
#elif SLIDING
//
using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");
var myOptions = new MyRateLimitOptions();
app.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
var slidingPolicy = "sliding";
app.UseRateLimiter(new RateLimiterOptions()
.AddSlidingWindowLimiter(policyName: slidingPolicy,
options =>
{
options.PermitLimit = myOptions.permitLimit;
options.Window = TimeSpan.FromSeconds(myOptions.window);
options.SegmentsPerWindow = myOptions.segmentsPerWindow;
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = myOptions.queueLimit;
}));
app.MapGet("/", () => Results.Ok($"Hello {GetTicks()}"))
.RequireRateLimiting(slidingPolicy);
app.Run();
//
#elif CONCUR
// Quicktest 10 users, 9 seconds -> 982 requests, 900 errors
//
using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");
var concurrencyPolicy = "Concurrency";
var myOptions = new MyRateLimitOptions();
app.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
app.UseRateLimiter(new RateLimiterOptions()
.AddConcurrencyLimiter(policyName: concurrencyPolicy,
options =>
{
options.PermitLimit = myOptions.permitLimit;
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = myOptions.queueLimit;
}));
app.MapGet("/", async () =>
{
await Task.Delay(500);
return Results.Ok($"Concurrency Limiter {GetTicks()}");
}).RequireRateLimiting(concurrencyPolicy);
app.Run();
//
#elif TOKEN
// Quicktest 20 users, 20 seconds -> 8965 requests 2,250 errors
//
using Microsoft.AspNetCore.RateLimiting;
using System.Threading.RateLimiting;
using WebRateLimitAuth.Models;
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");
var tokenPolicy = "token";
var myOptions = new MyRateLimitOptions();
app.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
app.UseRateLimiter(new RateLimiterOptions()
.AddTokenBucketLimiter(policyName: tokenPolicy,
options =>
{
options.TokenLimit = myOptions.tokenLimit;
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = myOptions.queueLimit;
options.ReplenishmentPeriod = TimeSpan.FromSeconds(myOptions.replenishmentPeriod);
options.TokensPerPeriod = myOptions.tokensPerPeriod;
options.AutoReplenishment = myOptions.autoReplenishment;
}));
app.MapGet("/", () => Results.Ok($"Token Limiter {GetTicks()}"))
.RequireRateLimiting(tokenPolicy);
app.Run();
//
#elif FIRST
//
using System.Globalization;
using System.Net;
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using WebRateLimitAuth;
using WebRateLimitAuth.Data;
using WebRateLimitAuth.Models;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ??
throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores();
builder.Services.Configure(
builder.Configuration.GetSection(MyRateLimitOptions.MyRateLimit));
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
//
// Preceding code removed for brevity.
app.UseAuthentication();
app.UseAuthorization();
var userPolicyName = "user";
var helloPolicy = "hello";
var myOptions = new MyRateLimitOptions();
var myConfigSection = app.Configuration.GetSection(MyRateLimitOptions.MyRateLimit);
myConfigSection.Bind(myOptions);
var options = new RateLimiterOptions()
{
OnRejected = (context, cancellationToken) =>
{
if (context.Lease.TryGetMetadata(MetadataName.RetryAfter, out var retryAfter))
{
context.HttpContext.Response.Headers.RetryAfter =
((int)retryAfter.TotalSeconds).ToString(NumberFormatInfo.InvariantInfo);
}
context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests;
context?.HttpContext?.RequestServices?.GetService()?
.CreateLogger("Microsoft.AspNetCore.RateLimitingMiddleware")
.LogWarning($"OnRejected: {GetUserEndPoint(context.HttpContext)}");
return new ValueTask();
}
}
.AddPolicy(helloPolicy)
.AddPolicy(userPolicyName, context =>
{
var username = "anonymous user";
if (context.User?.Identity?.IsAuthenticated is true)
{
username = context.User?.ToString()!;
}
return RateLimitPartition.GetSlidingWindowLimiter(username,
key => new SlidingWindowRateLimiterOptions
{
PermitLimit = myOptions.permitLimit,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = myOptions.queueLimit,
Window = TimeSpan.FromSeconds(myOptions.window),
SegmentsPerWindow = myOptions.segmentsPerWindow
});
});
options.GlobalLimiter = PartitionedRateLimiter.Create(context =>
{
IPAddress? remoteIPaddress = context?.Connection?.RemoteIpAddress;
if (!IPAddress.IsLoopback(remoteIPaddress!))
{
return RateLimitPartition.GetTokenBucketLimiter
(remoteIPaddress!, key =>
new TokenBucketRateLimiterOptions
{
TokenLimit = myOptions.tokenLimit2,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = myOptions.queueLimit,
ReplenishmentPeriod =
TimeSpan.FromSeconds(myOptions.replenishmentPeriod),
TokensPerPeriod = myOptions.tokensPerPeriod,
AutoReplenishment = myOptions.autoReplenishment
});
}
else
{
return RateLimitPartition.GetNoLimiter(IPAddress.Loopback);
}
});
app.UseRateLimiter(options);
app.MapRazorPages().RequireRateLimiting(userPolicyName);
app.MapDefaultControllerRoute();
static string GetUserEndPoint(HttpContext context) =>
$"User {context.User?.Identity?.Name ?? "Anonymous"} endpoint:{context.Request.Path}"
+ $" {context.Connection.RemoteIpAddress}";
static string GetTicks() => (DateTime.Now.Ticks & 0x11111).ToString("00000");
app.MapGet("/a", (HttpContext context) => $"{GetUserEndPoint(context)} {GetTicks()}")
.RequireRateLimiting(userPolicyName);
app.MapGet("/b", (HttpContext context) => $"{GetUserEndPoint(context)} {GetTicks()}")
.RequireRateLimiting(helloPolicy);
app.MapGet("/c", (HttpContext context) => $"{GetUserEndPoint(context)} {GetTicks()}");
app.Run();
//
//
#elif ADMIN
//
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Primitives;
using WebRateLimitAuth.Data;
using WebRateLimitAuth.Models;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection")
?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity(options =>
options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores();
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
//
var getPolicyName = "get";
var postPolicyName = "post";
var myOptions = new MyRateLimitOptions();
app.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
app.UseRateLimiter(new RateLimiterOptions()
.AddConcurrencyLimiter(policyName: getPolicyName,
options =>
{
options.PermitLimit = myOptions.permitLimit;
options.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
options.QueueLimit = myOptions.queueLimit;
})
.AddPolicy(policyName: postPolicyName, partitioner: httpContext =>
{
string userName = httpContext?.User?.Identity?.Name ?? string.Empty;
if (!StringValues.IsNullOrEmpty(userName))
{
return RateLimitPartition.GetTokenBucketLimiter(userName, key =>
new TokenBucketRateLimiterOptions
{
TokenLimit = myOptions.tokenLimit2,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = myOptions.queueLimit,
ReplenishmentPeriod =
TimeSpan.FromSeconds(myOptions.replenishmentPeriod),
TokensPerPeriod = myOptions.tokensPerPeriod,
AutoReplenishment = myOptions.autoReplenishment
});
}
else
{
return RateLimitPartition.GetTokenBucketLimiter("Anon", key =>
new TokenBucketRateLimiterOptions
{
TokenLimit = myOptions.tokenLimit,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = myOptions.queueLimit,
ReplenishmentPeriod =
TimeSpan.FromSeconds(myOptions.replenishmentPeriod),
TokensPerPeriod = myOptions.tokensPerPeriod,
AutoReplenishment = true
});
}
}));
//
static string GetUserEndPointMethod(HttpContext context) =>
$"Hello {context.User?.Identity?.Name ?? "Anonymous"} " +
$"Endpoint:{context.Request.Path} Method: {context.Request.Method}";
app.MapGet("/test", (HttpContext context) => $"{GetUserEndPointMethod(context)}")
.RequireRateLimiting(getPolicyName);
app.MapRazorPages().RequireRateLimiting(getPolicyName)
.RequireRateLimiting(postPolicyName);
app.MapDefaultControllerRoute();
app.Run();
//
#elif JWT
//
using System.Threading.RateLimiting;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.RateLimiting;
using Microsoft.Extensions.Primitives;
using WebRateLimitAuth.Models;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthorization();
builder.Services.AddAuthentication("Bearer").AddJwtBearer();
var app = builder.Build();
app.UseAuthorization();
var jwtPolicyName = "jwt";
var myOptions = new MyRateLimitOptions();
app.Configuration.GetSection(MyRateLimitOptions.MyRateLimit).Bind(myOptions);
var options = new RateLimiterOptions()
{
RejectionStatusCode = StatusCodes.Status429TooManyRequests
}
.AddPolicy(policyName: jwtPolicyName, partitioner: httpContext =>
{
var accessToken = httpContext?.Features?.Get()?
.AuthenticateResult?.Properties?.GetTokenValue("access_token")?.ToString()
?? string.Empty;
if (!StringValues.IsNullOrEmpty(accessToken))
{
return RateLimitPartition.GetTokenBucketLimiter(accessToken, key =>
new TokenBucketRateLimiterOptions
{
TokenLimit = myOptions.tokenLimit2,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = myOptions.queueLimit,
ReplenishmentPeriod =
TimeSpan.FromSeconds(myOptions.replenishmentPeriod),
TokensPerPeriod = myOptions.tokensPerPeriod,
AutoReplenishment = myOptions.autoReplenishment
});
}
else
{
return RateLimitPartition.GetTokenBucketLimiter("Anon", key =>
new TokenBucketRateLimiterOptions
{
TokenLimit = myOptions.tokenLimit,
QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
QueueLimit = myOptions.queueLimit,
ReplenishmentPeriod =
TimeSpan.FromSeconds(myOptions.replenishmentPeriod),
TokensPerPeriod = myOptions.tokensPerPeriod,
AutoReplenishment = true
});
}
});
app.UseRateLimiter(options);
app.MapGet("/", () => "Hello, World!");
app.MapGet("/jwt", (HttpContext context) => $"Hello {GetUserEndPointMethod(context)}")
.RequireRateLimiting(jwtPolicyName)
.RequireAuthorization();
app.MapPost("/post", (HttpContext context) => $"Hello {GetUserEndPointMethod(context)}")
.RequireRateLimiting(jwtPolicyName)
.RequireAuthorization();
app.Run();
static string GetUserEndPointMethod(HttpContext context) =>
$"Hello {context.User?.Identity?.Name ?? "Anonymous"} " +
$"Endpoint:{context.Request.Path} Method: {context.Request.Method}";
//
#endif