• AspNetCore 限流中间件IpRateLimitMiddleware 介绍


    IpRateLimitMiddleware(Github: AspNetCoreRateLimit) 是ASPNETCore的一个限流的中间件,用于控制客户端调用API的频次, 如果客户端频繁访问服务器,可以限制它的频率,已降低访问服务器端的压力。或者如果有爬虫在爬取关键数据,也可以限制某个/某些API或者某些IP的每天调取次数, 这样限制他爬取的速度。

    当然, 其实我要解决的是另外一个问题。 我们写的WebApi有时候会存在一些API,我们只希望其它内部应用来调用,比如,WebApi的HealthCheck, 我们就希望只有我们的中台可以定时调用来获取信息, 而前端是不能调用。这个我们就可以把内部的IP地址放到IpWhitelist配置项中, 并且限制特定的API调用次数为0次, 这样只有白名单里面的地址可以访问对应的端点, 如下所示。

    "GeneralRules": [
          {
            "Endpoint": "get:/api/healthstatus",
            "Period": "1s",
            "Limit": 0
          }]
    

    IPRateLimitMiddleWare详细使用说明,翻译来自于Github(AspNetCoreRateLimit)

    建立

    NuGet安装:

    Install-Package AspNetCoreRateLimit

    Startup.cs代码:

    public void ConfigureServices(IServiceCollection services)
    {
        // needed to load configuration from appsettings.json
        services.AddOptions();
    
        // needed to store rate limit counters and ip rules
        services.AddMemoryCache();
    
        //load general configuration from appsettings.json
        services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
    
        //load ip rules from appsettings.json
        services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
    
        // inject counter and rules stores
        services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
        services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
    
        // Add framework services.
        services.AddMvc();
    
            // https://github.com/aspnet/Hosting/issues/793
            // the IHttpContextAccessor service is not registered by default.
            // the clientId/clientIp resolvers use it.
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
    
            // configuration (resolvers, counter key builders)
            services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
    }
    
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseIpRateLimiting();
    
        app.UseMvc();
    }
    

    IPRateLimiting应该在其他中间件之前注册, 否则API请求计算可能不正确。

    如果您对应用程序进行负载平衡,则需要使用IDistributedCacheRedis或SQLServer,以便所有的kestrel实例都具有相同的速率限制存储。您应该像这样注入分布式存储,而不是使用MemoryCache:

    // inject counter and rules distributed cache stores
    services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
    services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
    

    配置和一般规则appsettings.json:

     "IpRateLimiting": {
        "EnableEndpointRateLimiting": false,
        "StackBlockedRequests": false,
        "RealIpHeader": "X-Real-IP",
        "ClientIdHeader": "X-ClientId",
        "HttpStatusCode": 429,
        "IpWhitelist": [ "127.0.0.1", "::1/10", "192.168.0.0/24" ],
        "EndpointWhitelist": [ "get:/api/license", "*:/api/status" ],
        "ClientWhitelist": [ "dev-id-1", "dev-id-2" ],
        "GeneralRules": [
          {
            "Endpoint": "*",
            "Period": "1s",
            "Limit": 2
          },
          {
            "Endpoint": "*",
            "Period": "15m",
            "Limit": 100
          },
          {
            "Endpoint": "*",
            "Period": "12h",
            "Limit": 1000
          },
          {
            "Endpoint": "*",
            "Period": "7d",
            "Limit": 10000
          }
        ]
      }
    

    如果EnableEndpointRateLimiting设置为false则全局将应用限制,并且仅应用具有作为端点的规则*。例如,如果您设置每秒5次调用的限制,则对任何端点的任何HTTP调用都将计入该限制。

    如果EnableEndpointRateLimiting设置为true,则限制将应用于每个端点,如{HTTP_Verb}{PATH}。例如,如果您为*:/api/values客户端设置每秒5个呼叫的限制,则可以GET /api/values每秒呼叫5次,但也可以呼叫5次PUT /api/values

    如果StackBlockedRequests设置为false,拒绝的API调用不会添加到调用次数计数器上。比如: 如果客户端每秒发出3个请求并且您设置了每秒一个调用的限制,则每分钟或每天计数器等其他限制将仅记录第一个调用,即成功的API调用。如果您希望被拒绝的API调用计入其他时间的显示(分钟,小时等),则必须设置StackBlockedRequeststrue

    RealIpHeader使用时,你的Kestrel 服务器背后是一个反向代理,如果你的代理服务器使用不同的页眉然后提取客户端IP X-Real-IP使用此选项来设置它。

    ClientIdHeader被用于提取白名单的客户端ID。如果此标头中存在客户端ID并且与ClientWhitelist中指定的值匹配,则不应用速率限制。

    覆盖特定IP appsettings.json的一般规则:

     "IpRateLimitPolicies": {
        "IpRules": [
          {
            "Ip": "84.247.85.224",
            "Rules": [
              {
                "Endpoint": "*",
                "Period": "1s",
                "Limit": 10
              },
              {
                "Endpoint": "*",
                "Period": "15m",
                "Limit": 200
              }
            ]
          },
          {
            "Ip": "192.168.3.22/25",
            "Rules": [
              {
                "Endpoint": "*",
                "Period": "1s",
                "Limit": 5
              },
              {
                "Endpoint": "*",
                "Period": "15m",
                "Limit": 150
              },
              {
                "Endpoint": "*",
                "Period": "12h",
                "Limit": 500
              }
            ]
          }
        ]
      }
    

    IP字段支持IP v4和v6值以及范围,如 "192.168.0.0/24", "fe80::/10" 或 "192.168.0.0-192.168.0.255"。

    如果您在appsettings.json配置文件中定义了静态速率策略,则需要在应用程序启动时为它们设定种子:

    public static async Task Main(string[] args)
    {
        IWebHost webHost = CreateWebHostBuilder(args).Build();
    
        using (var scope = webHost.Services.CreateScope())
        {
             // get the IpPolicyStore instance
             var ipPolicyStore = scope.ServiceProvider.GetRequiredService<IIpPolicyStore>();
    
             // seed IP data from appsettings
             await ipPolicyStore.SeedAsync();
        }
    
        await webHost.RunAsync();
    }
    

    定义速率限制规则

    规则由端点,期间和限制组成。

    端点格式是{HTTP_Verb}:{PATH},您可以使用asterix符号来定位任何HTTP谓词。

    期间格式是{INT}{PERIOD_TYPE},您可以使用以下期间类型之一:s, m, h, d

    限制格式是{LONG}

    示例:

    将所有端点的速率限制为每秒2次呼叫:

    {
     "Endpoint": "*",
     "Period": "1s",
     "Limit": 2
    }
    

    如果,在相同的IP中,在同一秒内,您将对api /值进行3次GET调用,则最后一次调用将被阻止。但是如果在同一秒内你也调用了PUT api /值,那么请求将会通过,因为它是一个不同的端点。当启用端点速率限制时,每个呼叫都是基于速率限制的{HTTP_Verb}{PATH}

    使用任何HTTP动词限制呼叫,/api/values每15分钟拨打5个呼叫:

    {
     "Endpoint": "*:/api/values",
     "Period": "15m",
     "Limit": 5
    }
    

    速率限制GET呼叫/api/values每小时5次呼叫:

    {
     "Endpoint": "get:/api/values",
     "Period": "1h",
     "Limit": 5
    }
    

    如果,在相同的IP中,在一小时内,您将对api /值进行6次GET调用,则最后一次调用将被阻止。但是如果在同一个小时内你也调用了GET api / values / 1,那么请求将会通过,因为它是一个不同的端点。

    行为

    当客户端进行HTTP调用时,IpRateLimitMiddleware : RateLimitMiddleware<IpRateLimitProcessor>执行以下操作:

    • 从请求对象中提取IP,客户端ID,HTTP谓词和URL,如果要实现自己的提取逻辑,可以覆盖该IpRateLimitMiddleware.ResolveIdentity方法或实现自定义IP /客户端解析器:
    public class CustomRateLimitConfiguration : RateLimitConfiguration
    {
        protected override void RegisterResolvers()
        {
            base.RegisterResolvers();
    
            ClientResolvers.Add(new ClientQueryStringResolveContributor(HttpContextAccessor, ClientRateLimitOptions.ClientIdHeader));
        }
    }
    
    • 在白名单中搜索IP,客户端ID和URL,如果匹配任何内容,则不执行任何操作。

    • 在IP规则中搜索匹配项,所有适用的规则按期间分组,对于每个期间使用的限制性最强的规则。

    • 在匹配的一般规则中搜索,如果匹配的一般规则具有IP规则中不存在的定义时段,则也使用此一般规则。

    • 对于每个匹配规则,速率限制计数器递增,如果计数器值大于规则限制,则请求被阻止。

    如果请求被阻止,则客户端会收到如下文本响应:

    Status Code: 429
    Retry-After: 58
    Content: API calls quota exceeded! maximum admitted 2 per 1m.
    
    

    您可以自定义通过改变这些选项的反应HttpStatusCodeQuotaExceededMessage,如果你想实现自己的回应,你可以重写IpRateLimitMiddleware.ReturnQuotaExceededResponse。的Retry-After报头值以秒表示。

    如果请求没有得到速率限制,那么匹配规则中定义的最长时间用于组成X-Rate-Limit标头,这些标头将在响应中注入:

    X-Rate-Limit-Limit: the rate limit period (eg. 1m, 12h, 1d)
    X-Rate-Limit-Remaining: number of request remaining 
    X-Rate-Limit-Reset: UTC date time (ISO 8601) when the limits resets
    
    

    客户端可以解析X-Rate-Limit-Reset这样的:

    DateTime resetDate = DateTime.ParseExact(resetHeader, "o", DateTimeFormatInfo.InvariantInfo);
    

    可以通过在appsettings.json中设置DisableRateLimitHeaders选项来禁用X-Rate-Limit和Retry-After标头true

    默认情况下,使用阻止请求进行记录Microsoft.Extensions.Logging.ILogger,如果要实现自己的日志记录,可以覆盖IpRateLimitMiddleware.LogBlockedRequest。当请求获得速率限制时,默认记录器会发出以下信息:

    info: AspNetCoreRateLimit.IpRateLimitMiddleware[0]
          Request get:/api/values from IP 84.247.85.224 has been blocked, quota 2/1m exceeded by 3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.
    
    

    在运行时更新速率限制

    在应用程序启动时,定义的IP速率限制规则将appsettings.json通过任一MemoryCacheClientPolicyStoreDistributedCacheIpPolicyStore根据您使用的缓存提供程序类型加载到缓存中。您可以访问控制器内的Ip策略存储并修改IP规则,如下所示:

    public class IpRateLimitController : Controller
    {
        private readonly IpRateLimitOptions _options;
        private readonly IIpPolicyStore _ipPolicyStore;
    
        public IpRateLimitController(IOptions<IpRateLimitOptions> optionsAccessor, IIpPolicyStore ipPolicyStore)
        {
            _options = optionsAccessor.Value;
            _ipPolicyStore = ipPolicyStore;
        }
    
        [HttpGet]
        public IpRateLimitPolicies Get()
        {
            return _ipPolicyStore.Get(_options.IpPolicyPrefix);
        }
    
        [HttpPost]
        public void Post()
        {
            var pol = _ipPolicyStore.Get(_options.IpPolicyPrefix);
    
            pol.IpRules.Add(new IpRateLimitPolicy
            {
                Ip = "8.8.4.4",
                Rules = new List<RateLimitRule>(new RateLimitRule[] {
                    new RateLimitRule {
                        Endpoint = "*:/api/testupdate",
                        Limit = 100,
                        Period = "1d" }
                })
            });
    
            _ipPolicyStore.Set(_options.IpPolicyPrefix, pol);
        }
    }
    

    这样,您可以将IP速率限制存储在数据库中,并在每个应用程序启动后将其推送到缓存中。

     
     
    12人点赞
     
    ASPNET
     
  • 相关阅读:
    后台管理、编辑器上传图片、修改用户头像、bbs小总结
    侧边栏制作成inclusion_tag、文章的点赞点踩、文章的评论
    登陆功能、bbs首页搭建、admin后台管理、首页文章展示、用户头像展示、图片防盗链、个人站点页面搭建、侧边栏展示功能、侧边栏筛选功能、将侧边栏制作成inclusion_tag
    表创建及同步、注册功能、登陆功能、搭建bbs首页
    毕设进度7
    毕设进度6
    毕设进度5
    毕设进度4
    毕设进度3
    学习进度2
  • 原文地址:https://www.cnblogs.com/webenh/p/11556327.html
Copyright © 2020-2023  润新知