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请求计算可能不正确。
如果您对应用程序进行负载平衡,则需要使用IDistributedCache
Redis或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调用计入其他时间的显示(分钟,小时等),则必须设置StackBlockedRequests
为true
。
在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.
您可以自定义通过改变这些选项的反应HttpStatusCode
和QuotaExceededMessage
,如果你想实现自己的回应,你可以重写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
通过任一MemoryCacheClientPolicyStore
或DistributedCacheIpPolicyStore
根据您使用的缓存提供程序类型加载到缓存中。您可以访问控制器内的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人点赞
AspNetCore 限流中间件IpRateLimitMiddleware 介绍的更多相关文章
- Asp.Net Core 7 preview 4 重磅新特性--限流中间件
前言 限流是应对流量暴增或某些用户恶意攻击等场景的重要手段之一,然而微软官方从未支持这一重要特性,AspNetCoreRateLimit这一第三方库限流库一般作为首选使用,然而其配置参数过于繁多,对使 ...
- ASP.NET Core WebApi AspNetCoreRateLimit 限流中间件学习
AspNetCoreRateLimit介绍: AspNetCoreRateLimit是ASP.NET核心速率限制框架,能够对WebApi,Mvc中控制限流,AspNetCoreRateLimit包包含 ...
- .NET服务治理之限流中间件-FireflySoft.RateLimit
概述 FireflySoft.RateLimit自2021年1月发布第一个版本以来,经历了多次升级迭代,目前已经十分稳定,被很多开发者应用到了生产系统中,最新发布的版本是3.0.0. Github:h ...
- Laravel 限流中间件 throttle 简析
1. 在Laravel 中配置 在 app\Http\Kernel.php 中,默认添加到中间件组 api 下,1分钟60次. 2. 限流原理 获取唯一请求来源,进行唯一标识(key) 获取该请求请求 ...
- 从-99打造Sentinel高可用集群限流中间件
接上篇Sentinel集群限流探索,上次简单提到了集群限流的原理,然后用官方给的 demo 简单修改了一下,可以正常运行生效. 这一次需要更进一步,基于 Sentinel 实现内嵌式集群限流的高可用方 ...
- AspNetCore添加API限流
最近发现有客户在大量的请求我们的接口,出于性能考虑遂添加了请求频率限制. 由于我们接口请求的是.Net Core写的API网关,所以可以直接添加一个中间件,中间件中使用请求的地址当key,通过配置中心 ...
- 【.NET Core项目实战-统一认证平台】第七章 网关篇-自定义客户端限流
[.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我介绍了如何在网关上增加自定义客户端授权功能,从设计到编码实现,一步一步详细讲解,相信大家也掌握了自定义中间件的开发技巧了,本篇我们 ...
- SpringBoot进阶教程(六十八)Sentinel实现限流降级
前面两篇文章nginx限流配置和SpringBoot进阶教程(六十七)RateLimiter限流,我们介绍了如何使用nginx和RateLimiter限流,这篇文章介绍另外一种限流方式---Senti ...
- 服务接口API限流 Rate Limit 续
一.前言 上一篇文章中粗浅的介绍使用Redis和基于令牌桶算法进行对服务接口API限流,本文介绍另一种算法---漏桶算法的应用.Nginx想必大家都有所了解是一个高性能的 HTTP 和反向代理服务器, ...
随机推荐
- refPoint 别名与指针
// refPoint.cpp : Defines the entry point for the console application. // #include "stdafx.h&qu ...
- list转json数组
lights为arraylist java后台代码: try { org.tempuri.TLight[] lights = phlightSoapProxy.getLights(); ...
- Buy Fruits-(构造)
https://ac.nowcoder.com/acm/contest/847/C 在blueland上有 n n个水果店,它们的编号依次为 0,1,2...n−1 0,1,2...n−1.奇妙的是, ...
- PHP获取一年有多少周和每周开始和结束日期
/*PHP获取当前日期是第几周和本周开始日期和本周结束日期*/ //$now = '2018-11-13';周二 public function getNowTimeInfo($now) { $str ...
- selenium 2 设置浏览器安装路径
selenium 2由于调用的是真实的浏览器,所以当你的浏览器不是安装在默认路径下,你就需要设定浏览器启动路径:若是默认路径,则程序中不需设定浏览器启动路径. 比如说用firefox进行测试 1. f ...
- Visual Studio 调试技巧---指针,元素个数
刚才,我在Visual Studio 中发现了一个以更好的方式调试指针的技巧.您可以在监视窗口中选择“n”,其中“n”是要显示的元素数.我认为下图是不言而喻的.
- Shared Virtual Memory (SVM) Functions
Description Shared Virtual Memory (SVM) (Glossary): An address space exposed to both the host and th ...
- WPF——OXY绘图_old
plotModel = new PlotModel() { Title = "数据统计", LegendTitle = "Max:红色,Min:黄色", Leg ...
- load average 定义(网易面试)
1. load average 定义 linux系统中的Load对当前CPU工作量的度量.简单的说是进程队列的长度. Load Average 就是一段时间 (1 分钟.5分钟.15分钟) 内平均 L ...
- thrift 是rpc协议
PC(Remote Procedure Call,远程过程调用)是建立在Socket之上的,出于一种类比的愿望,在一台机器上运行的主程序,可以调用另一台机器上准备好的子程序,就像LPC(本地过程调用) ...