【问题标题】:AspNetCoreRateLimit Does not use query parameters when matching rulesAspNetCoreRateLimit 匹配规则时不使用查询参数
【发布时间】:2020-08-29 18:30:58
【问题描述】:

我正在使用 AspNetCoreRateLimit 库和 Asp.Net Core 2.2 web api。我已将 IpRateLimiting 与Startup.cs 中的默认设置一起使用,如AspNetCoreRateLimit wiki 所示。

我有带有查询参数的 API 端点,它与 http GET 查询一起使用,如下所示(参见参数 startDatestopDate):

GET "https://host/api/endpoint/path?startDate=2020-04-04&stopDate=2020-04-04"

我只想将 唯一 个请求(具有唯一参数组合)限制为每小时 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"

问题是无论参数如何,我每小时只能发送 total 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 Yuthis 中提出的端点路由,因为有很多 API 客户端使用我的 API而且我不想引入任何重大更改。

【问题讨论】:

标签: c# asp.net-core throttling rate-limiting


【解决方案1】:

你可以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
          }
        ]
      }

这是测试结果:

【讨论】:

  • 感谢您的好回答。在我的情况下,更改控制器方法签名有点问题,因为有一堆 API 客户端使用我的端点,所以我不想引入任何重大更改。我必须看看是否可以创建自定义解析器。跨度>
【解决方案2】:

我找到了解决方案,从而回答了自己。就我而言,我无法按照another answer 中的建议更改控制器方法路由。

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>();

上面的代码 sn-p 修改了中间件的查询,因此看起来这些查询参数是路径的一部分。

所以不要这样:

/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
      }
    ]
  }

【讨论】:

  • 那你是怎么使用自定义中间件的,你是在StartUp上注册中间件的吗?
  • 感谢您的更新,我想您替换了这一行 app.UseIpRateLimiting();有了这个 app.UseMiddleware();
  • 没错,因为我自己制作了中间件。现在我的答案中有整个类 CustomIpRateLimitMiddleware。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-16
  • 1970-01-01
相关资源
最近更新 更多