• ASP.NET Core WebApi AspNetCoreRateLimit 限流中间件学习


    AspNetCoreRateLimit介绍:

    AspNetCoreRateLimit是ASP.NET核心速率限制框架,能够对WebApi,Mvc中控制限流,AspNetCoreRateLimit包包含IpRateLimit中间件和ClientRateLimit中间件,每个中间件都可以为不同的场景设置多个限,该框架的作者是stefanprodan,项目nuget地址是https://github.com/stefanprodan/AspNetCoreRateLimit

    对客户端IP限流控制。

    首先nuget安装 Install-Package AspNetCoreRateLimit ,在Startup中Code以下代码,添加服务和注入,其中的配置是什么;注释都有了。

    // This method gets called by the runtime. Use this method to add services to the container.
            public void ConfigureServices(IServiceCollection services)
            {
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
                //添加appsettings.json
                services.AddOptions();
                //需要存储速率和ip规则
                services.AddMemoryCache();
                //加载appsettings.json中的配置项 ,下面三项是加载general,rules
                services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
                services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
                //注入计时器和规则
                services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
                services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
                //添加框架服务
                services.AddMvc();
            }

    在Configure中配置RateLimit的启动

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
            public void Configure(IApplicationBuilder app, IHostingEnvironment env,ILoggerFactory loggerFactory)
            {
                loggerFactory.AddConsole(Configuration.GetSection("Logging"));
                loggerFactory.AddDebug();
                app.UseIpRateLimiting();
                if (env.IsDevelopment())
                    app.UseDeveloperExceptionPage();
                app.UseMvc();
            }

     我们还需要再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调用都计入这个限制,反之,如果它是true,那么该限制将应用于{端口}{path}中的每个端点。

    如果stackblockedrequest设置为false,则不会将拒绝调用添加到节流阀计数器,如果你要拒绝你必须设置为true;

    ClientidHeader用于提取白清单的客户端id,如果客户端id在这个里面,就不会应用速率限制。

    覆盖特定IP一般规则:

    "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值,我们还需要去定义速率限制规则

    规则由端点,期间和限制组成,示例(将所有的端点的速率限制每秒2次呼叫),那么定义如下:

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

     如果在同一端点,例如get/values在一秒中你调用了3次,那么第三次将会被阻止;但是如果说你在同一秒内还调用了Put/values那么不会阻止,因为他们不是在同一端点之中。在期间(Period)中,还有单位 s m h 等.

    有的时候我们对拦截有一定的自定义需求的时候,我们可以继承IpRateLimitMiddleware,如以下定义:

    public class CustomizationLimitMiddleware : IpRateLimitMiddleware
        {
            private readonly IpRateLimitOptions _options;
            private readonly IIpPolicyStore _ipPolicyStore;
    
            public CustomizationLimitMiddleware(RequestDelegate next, IOptions<IpRateLimitOptions> options, IRateLimitCounterStore counterStore, IIpPolicyStore policyStore, ILogger<IpRateLimitMiddleware> logger, IIpAddressParser ipParser = null) : base(next, options, counterStore, policyStore, logger, ipParser)
            {
                 _options = options.Value;
                _ipPolicyStore = policyStore;
            }
            public override ClientRequestIdentity SetIdentity(HttpContext httpContext)
            {
                var clientId = "anon";
                if (httpContext.Request.Headers.Keys.Contains(_options.ClientIdHeader, StringComparer.CurrentCultureIgnoreCase))
                {
                    clientId = httpContext.Request.Headers[_options.ClientIdHeader].First();
                }
    
                return new ClientRequestIdentity
                {
                    Path = httpContext.Request.Path.ToString().ToLowerInvariant(),
                    HttpVerb = httpContext.Request.Method.ToLowerInvariant(),
                    ClientId = clientId
                };
            }
        }

     行为

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

    • 从请求体中获取IP,客户端IP,Http信息,和一些URL,如果需要修改自己的提取逻辑,可以覆盖IpRateLimitMiddleware.SetIdentity。
    • 在白名单中搜索IP,客户端ID和URL,如果有匹配则不执行任何操作
    • 在IP规则中搜索匹配项,所有适用的规则按期间分组,对于每个期间使用最严格的规则
    • 在匹配的一般规则中搜索,如果匹配的一般规则具有IP规则中不存在的定义时间段,则也使用此一般规则
    • 对于每个匹配规则,速率限制计数器递增,如果计数器值大于规则限制,则请求被阻止

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

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

     如果请求没有得到速率限制,那么匹配规则中定义的最长周期用于组成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

    默认情况下,组织了客户端的调用我们都会记录到日志中,那么我们可以使用Microsoft.Extensions.Logging.ILogger,这个就略过了。

    我们有的时候需要添加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);
              //add
    		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" }
    			})
    		});
              //update
    		_ipPolicyStore.Set(_options.IpPolicyPrefix, pol);
    	}
    }

    这样呢,你可以将ip限制的规则放到数据库中再推送到缓存中。

  • 相关阅读:
    [Java] java中的异常处理
    Jmeter之定时器
    Jmeter之检查点
    Jmeter之集合点
    Jmeter之关联
    Jmeter之参数化
    Jmeter测试WebService接口
    Jmeter测试MySQL数据库
    Jmeter测试HTTP接口
    使用Postman对HTTP接口进行功能测试
  • 原文地址:https://www.cnblogs.com/ZaraNet/p/10119475.html
Copyright © 2020-2023  润新知