在ASP.NET Core 7 Web API中使用IP地址进行速率限制。

huangapple go评论79阅读模式
英文:

Using Rate Limiting in ASP.NET Core 7 Web API by IP address

问题

目前有一个NuGet包,可以通过IP地址进行速率限制,名为AspNetCoreRateLimit。然而,.NET 7引入了自己的速率限制版本,我想使用这个版本,因为它是由Microsoft发布的。我还没有找到一个好的例子,可以通过IP地址限制来模拟这个第三方包。我组合的代码如下:

  1. builder.Services.AddRateLimiter(options =>
  2. {
  3. options.RejectionStatusCode = 429;
  4. options.AddPolicy("api", httpContext =>
  5. {
  6. var ipAddress = httpContext.Connection.RemoteIpAddress?.ToString();
  7. if (ipAddress != null)
  8. {
  9. return RateLimitPartition.GetFixedWindowLimiter(ipAddress,
  10. partition => new FixedWindowRateLimiterOptions
  11. {
  12. AutoReplenishment = true,
  13. PermitLimit = 5,
  14. Window = TimeSpan.FromMinutes(1)
  15. });
  16. }
  17. else
  18. {
  19. return RateLimitPartition.GetNoLimiter("");
  20. }
  21. });
  22. });

然而,我遇到的问题是一个警告:"Warning CS8602: Dereference of a possibly null reference.",我猜想这是因为RemoteIpAddress可能为null。我想知道是否有更好的方法来使用这个新的.NET 7库实现IP速率限制。如果重要的话,我计划将这个Web API托管在Azure应用服务(Windows)中,并且由托管在应用服务中的SPA访问。

英文:

There is currently a nuget package that manages rate limiting by IP address called AspNetCoreRateLimit. However, .NET 7 introduced its own versino of rate limiting and I wanted to use this instead as its published by MS. I have not been able to find a good example that imitates this third party package by limiting by IP address. My code I put together is as follows:

  1. builder.Services.AddRateLimiter(options =>
  2. {
  3. options.RejectionStatusCode = 429;
  4. options.AddPolicy("api", httpContext =>
  5. {
  6. var IpAddress = httpContext.Connection.RemoteIpAddress.ToString();
  7. if (IpAddress != null)
  8. {
  9. return RateLimitPartition.GetFixedWindowLimiter(httpContext.Connection.RemoteIpAddress.ToString(),
  10. partition => new FixedWindowRateLimiterOptions
  11. {
  12. AutoReplenishment = true,
  13. PermitLimit = 5,
  14. Window = TimeSpan.FromMinutes(1)
  15. });
  16. }
  17. else
  18. {
  19. return RateLimitPartition.GetNoLimiter("");
  20. }
  21. });
  22. });

However, the issue I am getting is a warning "Warning CS8602: Dereference of a possibly null reference." which I assume is because RemoteIpAddress could be null. I am curious if there is a better way to implement this IP rate limiting using this new .NET 7 library. If it matter I am planning to host this web api in Azure app services (windows) and it is accessed by a SPA also hosted in an app service.

答案1

得分: 0

正如你提到的,关于可能为空引用的警告实际上不是一个错误。它来自于这行代码:

httpContext.Connection.RemoteIpAddress.ToString()

因为RemoteIpAddress属性可能为空(因此你的ToString()调用会抛出异常)。

然而,这与你实际问题无关,你的实际问题是:
"我想知道是否有更好的方法来使用这个新的.NET 7库来实现IP速率限制"

在Microsoft文档中直接提供了一个示例:
https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit?view=aspnetcore-7.0#limiter-with-onrejected-retryafter-and-globallimiter

具体来说,在该页面上可以找到以下代码:

limiterOptions.GlobalLimiter = PartitionedRateLimiter.Create<HttpContext, IPAddress>(context =>
{
IPAddress? remoteIpAddress = context.Connection.RemoteIpAddress;

  1. if (!IPAddress.IsLoopback(remoteIpAddress!))
  2. {
  3. return RateLimitPartition.GetTokenBucketLimiter
  4. (remoteIpAddress!, _ =>
  5. new TokenBucketRateLimiterOptions
  6. {
  7. TokenLimit = myOptions.TokenLimit2,
  8. QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
  9. QueueLimit = myOptions.QueueLimit,
  10. ReplenishmentPeriod = TimeSpan.FromSeconds(myOptions.ReplenishmentPeriod),
  11. TokensPerPeriod = myOptions.TokensPerPeriod,
  12. AutoReplenishment = myOptions.AutoReplenishment
  13. });
  14. }
  15. return RateLimitPartition.GetNoLimiter(IPAddress.Loopback);

});

这段代码设置了一个全局限制器(有点不相关),但如果你看他们的建议方法,它与你的方法非常相似。

他们并没有将IP地址转换为字符串,而是以不同的方式进行了检查。如果你想继续使用字符串并避免警告,你可以使用以下方法:

var ipAddressAsString = httpContext.Connection.RemoteIpAddress?.ToString();

这里我们使用了?.操作符。无论如何,我认为你的方法是正确的。

英文:

As you mentioned, the warning about the deference of a possibly null reference is not actually an error. It does come from this line:

  1. httpContext.Connection.RemoteIpAddress.ToString()

Because the RemoteIpAddress property can be null (and therefore your ToString() call would throw).

However, this is (in my opinion), unrelated to your actual question, which was:
" I am curious if there is a better way to implement this IP rate limiting using this new .NET 7 library"

There is an example of this directly in the Microsoft documentation:
https://learn.microsoft.com/en-us/aspnet/core/performance/rate-limit?view=aspnetcore-7.0#limiter-with-onrejected-retryafter-and-globallimiter

Specifically, this code can be found on that page:

  1. limiterOptions.GlobalLimiter = PartitionedRateLimiter.Create&lt;HttpContext, IPAddress&gt;(context =&gt;
  2. {
  3. IPAddress? remoteIpAddress = context.Connection.RemoteIpAddress;
  4. if (!IPAddress.IsLoopback(remoteIpAddress!))
  5. {
  6. return RateLimitPartition.GetTokenBucketLimiter
  7. (remoteIpAddress!, _ =&gt;
  8. new TokenBucketRateLimiterOptions
  9. {
  10. TokenLimit = myOptions.TokenLimit2,
  11. QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
  12. QueueLimit = myOptions.QueueLimit,
  13. ReplenishmentPeriod = TimeSpan.FromSeconds(myOptions.ReplenishmentPeriod),
  14. TokensPerPeriod = myOptions.TokensPerPeriod,
  15. AutoReplenishment = myOptions.AutoReplenishment
  16. });
  17. }
  18. return RateLimitPartition.GetNoLimiter(IPAddress.Loopback);
  19. });

This particular code is setting up a global limiter (sort of besides the point), but if you look at their suggested approach it's truly similar to what you have.

Instead of converting to a string, they are doing their checks a different way. If you wanted to stick with strings and get away from your warning, you could probably use the following:

  1. var ipAddressAsString = httpContext.Connection.RemoteIpAddress?.ToString();

Where we have the ?. operator being used. Regardless, I think you're on the right track with your approach.

huangapple
  • 本文由 发表于 2023年2月7日 03:42:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/75365849.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定