.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#setupFiddler開始測試
測試接口:
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/