.Net Core結合AspNetCoreRateLimit實現限流

.Net Core結合AspNetCoreRateLimit實現限流

前言
相信使用過WebApiThrottle的童鞋對AspNetCoreRateLimit應該不陌生,AspNetCoreRateLimit是一個ASP.NET Core速率限制的解決方案,旨在控制客戶端根據IP地址或客戶端ID向Web API或MVC應用發出的請求的速率。AspNetCoreRateLimit包含一個IpRateLimitMiddleware和ClientRateLimitMiddleware,每個中間件可以根據不同的場景配置限制允許IP或客戶端,自定義這些限制策略,也可以將限制策略應用在每​​個API URL或具體的HTTP Method上。

實踐
起初是因爲新做的項目中,有天查詢日誌發現,對外的幾個公共接口經常被“惡意”調用,考慮到接口安全性問題,增加限流策略。

AspNetCoreRateLimit GayHub:https://github.com/stefanprodan/AspNetCoreRateLimit

根據IP進行限流
通過nuget安裝AspNetCoreRateLimit,當前版本是3.0.5,因爲實際項目中用的都是分佈式緩存,在這裏不用內存存儲,而是結合Redis進行使用,內存存儲直接參考官方的Wiki就可以了。

Install-Package AspNetCoreRateLimit

Install-Package Microsoft.Extensions.Caching.Redis
在Startup.ConfigureServices中將服務和其他依賴注入

public void ConfigureServices(IServiceCollection services)

    {
        #region MVC
        services.AddMvc(
          options =>
          {
              options.UseCentralRoutePrefix(new RouteAttribute("api/"));
          }
          ).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        #endregion

        services.AddDistributedRedisCache(options =>
        {
            options.Configuration = "127.0.0.1:6379,password=123456,connectTimeout=5000,syncTimeout=10000"; 
            options.InstanceName = "WebRatelimit";
        }); 
        //加載配置
        services.AddOptions();
        //從appsettings.json獲取相應配置
        services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
        
        //注入計數器和規則存儲
        services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>();
        services.AddSingleton<IRateLimitCounterStore, DistributedCacheRateLimitCounterStore>();
        
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        //配置(計數器密鑰生成器)
        services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
    }

在Startup.Configure啓用

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }
        //啓用限流,需在UseMvc前面
        app.UseIpRateLimiting();
        app.UseMvc();
    }

爲了不影響appsettings.json的美觀吧,可以新建一個RateLimitConfig.json,並Program中啓動加載中增加

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>().ConfigureAppConfiguration((host,config)=> 
            {
                config.AddJsonFile($"RateLimitConfig.json", optional: true, reloadOnChange: true);
            });

RateLimitConfig.json 配置如下:

{
"IpRateLimiting": {

//false則全局將應用限制,並且僅應用具有作爲端點的規則* 。 true則限制將應用於每個端點,如{HTTP_Verb}{PATH}
"EnableEndpointRateLimiting": true,
//false則拒絕的API調用不會添加到調用次數計數器上
"StackBlockedRequests": false,
"RealIpHeader": "X-Real-IP",
"ClientIdHeader": "X-ClientId",
"HttpStatusCode": 200,
"QuotaExceededResponse": {
  "Content": "{{\"code\":429,\"msg\":\"訪問過於頻繁,請稍後重試\",\"data\":null}}",
  "ContentType": "application/json",
  "StatusCode": 200
},
"IpWhitelist": [ ],
"EndpointWhitelist": [],
"ClientWhitelist": [],
"GeneralRules": [
  {
    "Endpoint": "*:/api/values/test",
    "Period": "5s",
    "Limit": 3
  }
]

}
}

重要配置說明:

       QuotaExceededResponse 是自定義返回的內容,所以必須設置HttpStatusCode和StatusCode爲200。

GeneralRules是具體的策略,根據不同需求配置不同端點即可, Period的單位可以是s, m, h, d,Limint是單位時間內的允許訪問的次數;

IpWhitelist是IP白名單,本地調試或者UAT環境,可以加入相應的IP,略過策略的限制;

       EndpointWhitelist是端點白名單,如果全局配置了訪問策略,設置端點白名單相當於IP白名單一樣,略過策略的限制;

其他配置項請參考Wiki:https://github.com/stefanprodan/AspNetCoreRateLimit/wiki/IpRateLimitMiddleware#setup

Fiddler開始測試
測試接口:http://127.0.0.1:5000/api/values/Test

    [HttpGet]
    public object test()
    {
        return "ok";
    }

調用結果:

調用次數和剩餘調用次數在Head可以看到,(吃我一個鏈接:https://www.cnblogs.com/EminemJK/p/12720691.html

如果調用超過策略後,調用失敗,返回我們自定義的內容

在Redis客戶端可以看到策略的一些情況,

 其他
通常在項目中,Authorization授權是少不了了,加入限流後,在被限流的接口調用後,限流攔截器使得跨域策略失效,故重寫攔截器中間件,繼承IpRateLimitMiddleware 即可:

public class IPLimitMiddleware : IpRateLimitMiddleware
{
    public IPLimitMiddleware(RequestDelegate next, IOptions<IpRateLimitOptions> options, IRateLimitCounterStore counterStore, IIpPolicyStore policyStore, IRateLimitConfiguration config, ILogger<IpRateLimitMiddleware> logger)
        : base(next, options, counterStore, policyStore, config, logger)
    {
    }

    public override Task ReturnQuotaExceededResponse(HttpContext httpContext, RateLimitRule rule, string retryAfter)
    {
        httpContext.Response.Headers.Append("Access-Control-Allow-Origin", "*");
        return base.ReturnQuotaExceededResponse(httpContext, rule, retryAfter);
    }
}

然後修改Startup.Configure,

    //啓用限流,需在UseMvc前面
    //app.UseIpRateLimiting();
    app.UseMiddleware<IPLimitMiddleware>();
    app.UseMvc();

特別需要注意的坑是,在其他文章的教程中,他們會寫成:

    app.UseMiddleware<IPLimitMiddleware>().UseIpRateLimiting();//錯誤的演示 https://www.cnblogs.com/EminemJK/p/12720691.html

這些寫你測試的時候會發現,

X-Rate-Limit-Remaining 遞減量會變成2,也不是遞減1,舉栗子,配置如下:

    "Endpoint": "*:/api/values/test",
    "Period": "3s",
    "Limit": 1

表示3秒內可以訪問的次數是1一次,當發生調用的時候會直接返回被限制的提示,而不能正常訪問接口。

最後
AspNetCoreRateLimit還可以根據客戶端ID進行配置策略,具體可以看一下官方的Wiki吧。

作者:EminemJK(山治先生)
出處:https://www.cnblogs.com/EminemJK/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章