.NET 7按IP限流问题:特定端点1分钟3次请求配置无效
解决.NET Core 7中按IP限流"forgot-password"端点无效的问题
你的限流策略未生效的核心原因是分区键选择错误:原代码中用context.User.Identity?.Name(匿名用户为空)和context.Request.Headers.Host(这是服务器的Host头,而非客户端IP)作为分区键,导致所有请求共用同一个限流桶,根本没按客户端IP区分。
修复步骤
1. 正确获取客户端IP
需要从HttpContext中提取真实客户端IP,同时兼容反向代理(如Nginx、IIS)场景:
// 可放在Program.cs顶部或单独工具类中 static string GetClientIp(HttpContext context) { // 优先读取反向代理转发的真实IP(X-Forwarded-For) var forwardedIp = context.Request.Headers["X-Forwarded-For"].FirstOrDefault(); if (!string.IsNullOrWhiteSpace(forwardedIp)) { // X-Forwarded-For可能包含多个IP(代理链),取第一个 return forwardedIp.Split(',').First().Trim(); } // 无代理时直接获取连接的远程IP return context.Connection.RemoteIpAddress?.ToString() ?? "unknown-client-ip"; }
2. 修改限流策略的分区键
将限流策略的partitionKey替换为客户端IP:
builder.Services.AddRateLimiter(options => { options.AddPolicy("testRatelimit", context => RateLimitPartition.GetFixedWindowLimiter( partitionKey: GetClientIp(context), // 按客户端IP分区 factory: partition => new FixedWindowRateLimiterOptions { AutoReplenishment = true, PermitLimit = 3, QueueLimit = 0, Window = TimeSpan.FromMinutes(1) })); options.OnRejected = async (context, token) => { context.HttpContext.Response.StatusCode = StatusCodes.Status429TooManyRequests; await context.HttpContext.Response.WriteAsync("请求过于频繁,请1分钟后重试。", cancellationToken: token); }; });
3. 适配反向代理环境(可选但重要)
如果应用部署在反向代理之后,需要配置转发头才能获取真实客户端IP,否则拿到的是代理服务器的IP:
// 在builder.Build()之前添加转发头配置 builder.Services.Configure<ForwardedHeadersOptions>(options => { options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; // 添加信任的代理IP(根据部署环境调整,比如本地测试用127.0.0.1) options.KnownProxies.Add(IPAddress.Parse("127.0.0.1")); }); // 在app.UseRateLimiter()之前启用转发头中间件 var app = builder.Build(); app.UseForwardedHeaders(); app.UseRateLimiter();
4. 确认控制器配置
你的控制器代码无需修改,[EnableRateLimiting("testRatelimit")]已正确应用到forgot-password端点,[AllowAnonymous]不影响限流策略生效。
验证
启动应用后,用同一个IP在1分钟内发送超过3次请求,会收到429状态码和提示信息,说明限流已生效。
内容的提问来源于stack exchange,提问作者Nic
相关产品推荐
相关产品推荐

