AspNetCoreRateLimit 匹配规则时不使用查询参数
AspNetCoreRateLimit Does not use query parameters when matching rules
我正在使用 AspNetCoreRateLimit library with Asp.Net Core 2.2 web api. I've taken IpRateLimiting into use with it's default settings in Startup.cs
as seen AspNetCoreRateLimit wiki。
我有 API 个带有查询参数的端点,它与 http GET 查询一起使用,如下所示(请参阅参数 startDate
和 stopDate
):
GET "https://host/api/endpoint/path?startDate=2020-04-04&stopDate=2020-04-04"
我只想将 unique 请求(具有唯一参数组合)限制为每小时 5 个请求。因此,例如,以下场景在 1 小时内应该是可能的:
5 times: GET "https://host/api/endpoint/path?startDate=2020-04-04&stopDate=2020-04-04"
5 times: GET "https://host/api/endpoint/path?startDate=2020-04-05&stopDate=2020-04-05"
问题是无论参数如何,我每小时只能发送总共 5 个请求。
以下是我在 appsettings.json 中的 IpRateLimiting 设置。
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIPHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*:/api/endpoint/path",
"Period": "1h",
"Limit": 5
}
]
}
请注意,我不想更改@Yongqing Yu中提出的端点路由,因为有很多API 客户使用我的 API,我不想引入任何重大更改。
可以change the route
对应的action,把参数直接变成路径的一部分,如'https://host/api/endpoint/path/2020-04-04/2020-04-04'
,这样GeneralRules
中的Endpoint
就可以满足*
.
你的情况
可以参考this.
这是我的演示:
[Route("api/[controller]")]
[ApiController]
public class DefaultController : ControllerBase
{
[HttpGet("Test/{startDate}/{stopDate}")]
public string Test(string startDate, string stopDate)
{
return "Ok";
}
}
appsettings.json:
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIPHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*:/api/default/Test/*",
"Period": "1h",
"Limit": 5
}
]
}
测试结果如下:
我找到了解决方案,从而对自己做出了回答。就我而言,我无法按照 .
中的建议更改控制器方法路由
如上所述 here 可以实现自己的路径提取逻辑。我编写了自定义 IpRateLimitMiddleware 并重写了 ResolveIdentity-method,如下所示:
public class CustomIpRateLimitMiddleware : IpRateLimitMiddleware
{
private readonly ILogger<CustomIpRateLimitMiddleware> _logger;
private readonly IRateLimitConfiguration _config;
public CustomIpRateLimitMiddleware(RequestDelegate next,
IOptions<IpRateLimitOptions> options,
IRateLimitCounterStore counterStore,
IIpPolicyStore policyStore,
IRateLimitConfiguration config,
ILogger<CustomIpRateLimitMiddleware> logger)
: base(next, options, counterStore, policyStore, config, logger)
{
_config = config;
_logger = logger;
}
public override ClientRequestIdentity ResolveIdentity(HttpContext httpContext)
{
var identity = base.ResolveIdentity(httpContext);
if (httpContext.Request.Query == null && !httpContext.Request.Query.Any())
{
return identity;
}
StringBuilder path = new StringBuilder(httpContext.Request.Path.ToString().ToLowerInvariant());
foreach (var parameter in httpContext.Request.Query)
{
path.Append("/" + parameter.Value);
}
identity.Path = path.ToString();
return identity;
}
}
这在 Startup.cs 中初始化如下:
ConfigureServices
-方法:
services.AddOptions();
services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
Configure
-方法:
app.UseMiddleware<CustomIpRateLimitMiddleware>();
上面的代码片段修改了对中间件的查询,因此这些查询参数看起来像是路径的一部分。
所以不是这个:
/api/endpoint/path?startDate=2020-04-04&stopDate=2020-04-04"
AspNetCoreRateLimit 获取的路径格式如下:
/api/endpoint/path/2020-04-04/2020-04-04
..现在我的速率限制配置可以是这样的:
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIPHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*:/api/path/*",
"Period": "1h",
"Limit": 5
}
]
}
我正在使用 AspNetCoreRateLimit library with Asp.Net Core 2.2 web api. I've taken IpRateLimiting into use with it's default settings in Startup.cs
as seen AspNetCoreRateLimit wiki。
我有 API 个带有查询参数的端点,它与 http GET 查询一起使用,如下所示(请参阅参数 startDate
和 stopDate
):
GET "https://host/api/endpoint/path?startDate=2020-04-04&stopDate=2020-04-04"
我只想将 unique 请求(具有唯一参数组合)限制为每小时 5 个请求。因此,例如,以下场景在 1 小时内应该是可能的:
5 times: GET "https://host/api/endpoint/path?startDate=2020-04-04&stopDate=2020-04-04"
5 times: GET "https://host/api/endpoint/path?startDate=2020-04-05&stopDate=2020-04-05"
问题是无论参数如何,我每小时只能发送总共 5 个请求。
以下是我在 appsettings.json 中的 IpRateLimiting 设置。
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIPHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*:/api/endpoint/path",
"Period": "1h",
"Limit": 5
}
]
}
请注意,我不想更改@Yongqing Yu
可以change the route
对应的action,把参数直接变成路径的一部分,如'https://host/api/endpoint/path/2020-04-04/2020-04-04'
,这样GeneralRules
中的Endpoint
就可以满足*
.
可以参考this.
这是我的演示:
[Route("api/[controller]")]
[ApiController]
public class DefaultController : ControllerBase
{
[HttpGet("Test/{startDate}/{stopDate}")]
public string Test(string startDate, string stopDate)
{
return "Ok";
}
}
appsettings.json:
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIPHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*:/api/default/Test/*",
"Period": "1h",
"Limit": 5
}
]
}
测试结果如下:
我找到了解决方案,从而对自己做出了回答。就我而言,我无法按照
如上所述 here 可以实现自己的路径提取逻辑。我编写了自定义 IpRateLimitMiddleware 并重写了 ResolveIdentity-method,如下所示:
public class CustomIpRateLimitMiddleware : IpRateLimitMiddleware
{
private readonly ILogger<CustomIpRateLimitMiddleware> _logger;
private readonly IRateLimitConfiguration _config;
public CustomIpRateLimitMiddleware(RequestDelegate next,
IOptions<IpRateLimitOptions> options,
IRateLimitCounterStore counterStore,
IIpPolicyStore policyStore,
IRateLimitConfiguration config,
ILogger<CustomIpRateLimitMiddleware> logger)
: base(next, options, counterStore, policyStore, config, logger)
{
_config = config;
_logger = logger;
}
public override ClientRequestIdentity ResolveIdentity(HttpContext httpContext)
{
var identity = base.ResolveIdentity(httpContext);
if (httpContext.Request.Query == null && !httpContext.Request.Query.Any())
{
return identity;
}
StringBuilder path = new StringBuilder(httpContext.Request.Path.ToString().ToLowerInvariant());
foreach (var parameter in httpContext.Request.Query)
{
path.Append("/" + parameter.Value);
}
identity.Path = path.ToString();
return identity;
}
}
这在 Startup.cs 中初始化如下:
ConfigureServices
-方法:
services.AddOptions();
services.AddMemoryCache();
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
Configure
-方法:
app.UseMiddleware<CustomIpRateLimitMiddleware>();
上面的代码片段修改了对中间件的查询,因此这些查询参数看起来像是路径的一部分。
所以不是这个:
/api/endpoint/path?startDate=2020-04-04&stopDate=2020-04-04"
AspNetCoreRateLimit 获取的路径格式如下:
/api/endpoint/path/2020-04-04/2020-04-04
..现在我的速率限制配置可以是这样的:
"IpRateLimiting": {
"EnableEndpointRateLimiting": true,
"StackBlockedRequests": false,
"RealIPHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 429,
"GeneralRules": [
{
"Endpoint": "*:/api/path/*",
"Period": "1h",
"Limit": 5
}
]
}