AddRateLimiter
services.AddRateLimiter(options =>
{
options.RejectionStatusCode = StatusCodes.Status429TooManyRequests;
options.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, string>(httpContext =>
{
string ipAddress = GetIPAddress(httpContext);
return RateLimitPartition.GetFixedWindowLimiter(
partitionKey: ipAddress,
factory: _ => new FixedWindowRateLimiterOptions
{
PermitLimit = 70,
Window = TimeSpan.FromSeconds(60),
}
);
});
});
Methods to get IP address
public static string GetIPAddress(HttpContext httpContext)
{
string ipAddress = GetRemoteHostIpAddressUsingXForwardedFor(httpContext)?.ToString();
if (string.IsNullOrEmpty(ipAddress))
ipAddress = httpContext.Connection.RemoteIpAddress?.ToString();
if (string.IsNullOrEmpty(ipAddress))
ipAddress = GetRemoteHostIpAddressUsingXRealIp(httpContext)?.ToString();
return ipAddress;
}
private static IPAddress GetRemoteHostIpAddressUsingXForwardedFor(HttpContext httpContext)
{
IPAddress remoteIpAddress = null;
string forwardedFor = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
if (string.IsNullOrEmpty(forwardedFor) == false)
{
List<string> ipList = forwardedFor
.Split(',', StringSplitOptions.RemoveEmptyEntries)
.Select(s => s.Trim())
.ToList();
foreach (string ip in ipList)
{
if (IPAddress.TryParse(ip, out var address) &&
(address.AddressFamily is AddressFamily.InterNetwork or AddressFamily.InterNetworkV6))
{
remoteIpAddress = address;
break;
}
}
}
return remoteIpAddress;
}
private static IPAddress GetRemoteHostIpAddressUsingXRealIp(HttpContext httpContext)
{
bool xRealIpExists = httpContext.Request.Headers.TryGetValue("X-Real-IP", out var xRealIp);
if (xRealIpExists)
{
if (!IPAddress.TryParse(xRealIp, out IPAddress address))
return null;
bool isValidIP = address.AddressFamily is AddressFamily.InterNetwork or AddressFamily.InterNetworkV6;
if (isValidIP)
return address;
}
return null;
}
UseRateLimiter
app.UseRateLimiter();