asp.net-core
Tariefbeperking
Zoeken…
Opmerkingen
AspNetCoreRateLimit is een open source ASP.NET Core-snelheidsbeperkende oplossing die is ontworpen om de snelheid van aanvragen te regelen die clients kunnen indienen bij een Web API- of MVC-app op basis van IP-adres of client-ID.
Tariefbeperking op basis van IP van client
Met IpRateLimit middleware kunt u meerdere limieten instellen voor verschillende scenario's, zoals het toestaan van een IP- of IP-bereik om een maximaal aantal oproepen te doen in een tijdsinterval zoals per seconde, 15 minuten, enz. U kunt deze limieten definiëren om alle verzoeken aan een API of u kunt de limieten voor elk URL-pad of HTTP-werkwoord en -pad instellen.
Opstelling
NuGet-installatie :
Install-Package AspNetCoreRateLimit
Startup.cs-code :
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(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseIpRateLimiting(); app.UseMvc(); }
U moet de middleware registreren vóór alle andere componenten behalve loggerFactory.
Als u uw app laadt, moet u IDistributedCache
gebruiken met IDistributedCache
of SQLServer, zodat alle torenvalkinstanties dezelfde snelheidslimietopslag hebben. In plaats van de geheugenopslag moet u de gedistribueerde winkels als volgt injecteren:
// inject counter and rules distributed cache stores services.AddSingleton<IIpPolicyStore, DistributedCacheIpPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Configuratie en algemene regels 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 } ] }
Als EnableEndpointRateLimiting
is ingesteld op false
zijn de limieten globaal van toepassing en zijn alleen regels met als eindpunt *
van toepassing. Als u bijvoorbeeld een limiet van 5 oproepen per seconde instelt, telt elke HTTP-oproep naar elk eindpunt mee voor die limiet.
Als EnableEndpointRateLimiting
is ingesteld op true
, gelden de limieten voor elk eindpunt zoals in {HTTP_Verb}{PATH}
. Als u bijvoorbeeld een limiet van 5 oproepen per seconde *:/api/values
voor *:/api/values
een client GET /api/values
5 keer per seconde oproepen, maar ook 5 keer PUT /api/values
.
Als StackBlockedRequests
is ingesteld op false
geweigerde oproepen, worden deze niet toegevoegd aan de gashendel. Als een klant 3 verzoeken per seconde indient en u een limiet van één oproep per seconde hebt ingesteld, nemen andere limieten zoals per minuut of per dagtellers alleen de eerste oproep op, die niet werd geblokkeerd. Als u wilt dat afgewezen aanvragen meetellen voor de andere limieten, moet u StackBlockedRequests
op true
.
De RealIpHeader
wordt gebruikt om het client-IP-adres te extraheren wanneer uw Kestrel-server zich achter een reverse proxy bevindt. Als uw proxy een andere header gebruikt, gebruikt X-Real-IP
deze optie om het in te stellen.
De ClientIdHeader
wordt gebruikt om de client-ID voor de witte lijst te extraheren. Als een client-ID aanwezig is in deze header en overeenkomt met een waarde die is opgegeven in ClientWhitelist, worden er geen tarieflimieten toegepast.
Algemene regels voor specifieke IP's appsettings.json overschrijven :
"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 } ] } ] }
Het IP-veld ondersteunt IP v4- en v6-waarden en bereiken zoals "192.168.0.0/24", "fe80 :: / 10" of "192.168.0.0-192.168.0.255".
Tarieflimietregels definiëren
Een regel bestaat uit een eindpunt, een periode en een limiet.
Eindpuntindeling is {HTTP_Verb}:{PATH}
, u kunt elk HTTP-werkwoord targeten met het asterix-symbool.
Periode-indeling is {INT}{PERIOD_TYPE}
, u kunt een van de volgende periodetypen gebruiken: s, m, h, d
.
Limietindeling is {LONG}
.
Voorbeelden :
Tarieflimiet alle eindpunten tot 2 oproepen per seconde:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Als u vanaf hetzelfde IP-adres in dezelfde seconde 3 GET-oproepen naar api / waarden uitvoert, wordt de laatste oproep geblokkeerd. Maar als u in dezelfde seconde ook PUT api / waarden aanroept, zal het verzoek doorgaan omdat het een ander eindpunt is. Wanneer eindpuntsnelheidsbegrenzing is ingeschakeld, is elk gesprek {HTTP_Verb}{PATH}
gebaseerd op {HTTP_Verb}{PATH}
.
Tarieflimietoproepen met elk HTTP-werkwoord naar /api/values
tot 5 oproepen per 15 minuten:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Tarieflimiet GET oproep naar /api/values
tot 5 oproepen per uur:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Als u vanaf hetzelfde IP-adres binnen een uur 6 GET-oproepen naar api / waarden uitvoert, wordt de laatste oproep geblokkeerd. Maar als je in hetzelfde uur ook GET api / waarden / 1 aanroept, zal het verzoek doorgaan omdat het een ander eindpunt is.
Gedrag
Wanneer een client een HTTP-oproep doet, doet de IpRateLimitMiddleware het volgende:
- haalt het IP, client-ID, HTTP-werkwoord en de URL uit het
IpRateLimitMiddleware.SetIdentity
, als u uw eigen extractielogica wilt implementeren, kunt u deIpRateLimitMiddleware.SetIdentity
overschrijven.IpRateLimitMiddleware.SetIdentity
- zoekt naar het IP, klant-ID en URL in de witte lijsten, indien er overeenkomsten zijn, wordt er geen actie ondernomen
- zoekt in de IP-regels voor een overeenkomst, alle toepasselijke regels zijn gegroepeerd op periode, voor elke periode wordt de meest beperkende regel gebruikt
- zoekt in de algemene regels naar een overeenkomst, als een algemene regel die overeenkomt een gedefinieerde periode heeft die niet aanwezig is in de IP-regels, wordt deze algemene regel ook gebruikt
- voor elke overeenkomende regel wordt de snelheidslimietteller verhoogd, als de tellerwaarde groter is dan de regellimiet, wordt het verzoek geblokkeerd
Als het verzoek wordt geblokkeerd, ontvangt de client een sms-reactie zoals deze:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
U kunt het antwoord aanpassen door deze opties HttpStatusCode
en QuotaExceededMessage
. Als u uw eigen antwoord wilt implementeren, kunt u het IpRateLimitMiddleware.ReturnQuotaExceededResponse
overschrijven. De Retry-After
wordt uitgedrukt in seconden.
Als het verzoek geen snelheidsbeperking krijgt, wordt de langste periode die is gedefinieerd in de overeenkomende regels gebruikt om de X-Rate-Limit-headers samen te stellen, deze headers worden geïnjecteerd in het antwoord:
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 when the limits resets
Standaard worden geblokkeerde aanvragen vastgelegd met Microsoft.Extensions.Logging.ILogger
, als u uw eigen logboekregistratie wilt implementeren, kunt u de IpRateLimitMiddleware.LogBlockedRequest
overschrijven. De standaard logger zendt de volgende informatie uit wanneer een verzoek snelheidsbeperking krijgt:
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.
Snelheidslimieten bijwerken tijdens runtime
Bij het opstarten van de toepassing worden de IP-snelheidslimietregels gedefinieerd in appsettings.json
in de cache geladen door MemoryCacheClientPolicyStore
of DistributedCacheIpPolicyStore
afhankelijk van het type cache-provider dat u gebruikt. U kunt toegang krijgen tot de Ip policy store in een controller en de IP-regels als volgt wijzigen:
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); } }
Op deze manier kunt u de IP-snelheidslimieten in een database opslaan en na elke start van de app in cache plaatsen.
Tariefbeperking op basis van klant-ID
Met ClientRateLimit middleware kunt u meerdere limieten instellen voor verschillende scenario's, zoals het toestaan van een client om een maximaal aantal oproepen te doen in een tijdsinterval zoals per seconde, 15 minuten, enz. U kunt deze limieten definiëren om alle verzoeken aan een API of u aan te pakken kan de limieten voor elk URL-pad of HTTP-werkwoord en -pad bereiken.
Opstelling
NuGet-installatie :
Install-Package AspNetCoreRateLimit
Startup.cs-code :
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<ClientRateLimitOptions>(Configuration.GetSection("ClientRateLimiting")); //load client rules from appsettings.json services.Configure<ClientRateLimitPolicies>(Configuration.GetSection("ClientRateLimitPolicies")); // inject counter and rules stores services.AddSingleton<IClientPolicyStore, MemoryCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>(); // Add framework services. services.AddMvc(); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { loggerFactory.AddConsole(Configuration.GetSection("Logging")); loggerFactory.AddDebug(); app.UseClientRateLimiting(); app.UseMvc(); }
U moet de middleware registreren vóór alle andere componenten behalve loggerFactory.
Als u uw app laadt, moet u IDistributedCache
gebruiken met IDistributedCache
of SQLServer, zodat alle torenvalkinstanties dezelfde snelheidslimietopslag hebben. In plaats van de geheugenopslag moet u de gedistribueerde winkels als volgt injecteren:
// inject counter and rules distributed cache stores services.AddSingleton<IClientPolicyStore, DistributedCacheClientPolicyStore>(); services.AddSingleton<IRateLimitCounterStore,DistributedCacheRateLimitCounterStore>();
Configuratie en algemene regels appsettings.json :
"ClientRateLimiting": { "EnableEndpointRateLimiting": false, "StackBlockedRequests": false, "ClientIdHeader": "X-ClientId", "HttpStatusCode": 429, "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 } ] }
Als EnableEndpointRateLimiting
is ingesteld op false
zijn de limieten globaal van toepassing en zijn alleen regels met als eindpunt *
van toepassing. Als u bijvoorbeeld een limiet van 5 oproepen per seconde instelt, telt elke HTTP-oproep naar elk eindpunt mee voor die limiet.
Als EnableEndpointRateLimiting
is ingesteld op true
, gelden de limieten voor elk eindpunt zoals in {HTTP_Verb}{PATH}
. Als u bijvoorbeeld een limiet van 5 oproepen per seconde *:/api/values
voor *:/api/values
een client GET /api/values
5 keer per seconde oproepen, maar ook 5 keer PUT /api/values
.
Als StackBlockedRequests
is ingesteld op false
geweigerde oproepen, worden deze niet toegevoegd aan de gashendel. Als een klant 3 verzoeken per seconde indient en u een limiet van één oproep per seconde hebt ingesteld, nemen andere limieten zoals per minuut of per dagtellers alleen de eerste oproep op, die niet werd geblokkeerd. Als u wilt dat afgewezen aanvragen meetellen voor de andere limieten, moet u StackBlockedRequests
op true
.
De ClientIdHeader
wordt gebruikt om de client-ID te extraheren. Als een client-ID aanwezig is in deze header en overeenkomt met een waarde die is opgegeven in ClientWhitelist, worden er geen tarieflimieten toegepast.
Algemene regels voor specifieke clients appsettings.json overschrijven :
"ClientRateLimitPolicies": { "ClientRules": [ { "ClientId": "client-id-1", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 10 }, { "Endpoint": "*", "Period": "15m", "Limit": 200 } ] }, { "Client": "client-id-2", "Rules": [ { "Endpoint": "*", "Period": "1s", "Limit": 5 }, { "Endpoint": "*", "Period": "15m", "Limit": 150 }, { "Endpoint": "*", "Period": "12h", "Limit": 500 } ] } ] }
Tarieflimietregels definiëren
Een regel bestaat uit een eindpunt, een periode en een limiet.
Eindpuntindeling is {HTTP_Verb}:{PATH}
, u kunt elk HTTP-werkwoord targeten met het asterix-symbool.
Periode-indeling is {INT}{PERIOD_TYPE}
, u kunt een van de volgende periodetypen gebruiken: s, m, h, d
.
Limietindeling is {LONG}
.
Voorbeelden :
Tarieflimiet alle eindpunten tot 2 oproepen per seconde:
{ "Endpoint": "*", "Period": "1s", "Limit": 2 }
Als een client in dezelfde seconde 3 GET-oproepen naar api / waarden doet, wordt de laatste oproep geblokkeerd. Maar als hij in dezelfde seconde ook PUT api / waarden aanroept, zal het verzoek doorgaan omdat het een ander eindpunt is. Wanneer eindpuntsnelheidsbegrenzing is ingeschakeld, is elk gesprek {HTTP_Verb}{PATH}
gebaseerd op {HTTP_Verb}{PATH}
.
Tarieflimietoproepen met elk HTTP-werkwoord naar /api/values
tot 5 oproepen per 15 minuten:
{ "Endpoint": "*:/api/values", "Period": "15m", "Limit": 5 }
Tarieflimiet GET oproep naar /api/values
tot 5 oproepen per uur:
{ "Endpoint": "get:/api/values", "Period": "1h", "Limit": 5 }
Als een client binnen een uur 6 GET-oproepen naar api / waarden uitvoert, wordt de laatste oproep geblokkeerd. Maar als hij in hetzelfde uur ook GET api / values / 1 aanroept, zal het verzoek doorgaan omdat het een ander eindpunt is.
Gedrag
Wanneer een client een HTTP-aanroep doet, doet ClientRateLimitMiddleware het volgende:
- haalt het client-ID, HTTP-werkwoord en de URL uit het
ClientRateLimitMiddleware.SetIdentity
, als u uw eigen extractielogica wilt implementeren, kunt u deClientRateLimitMiddleware.SetIdentity
overschrijven.ClientRateLimitMiddleware.SetIdentity
- zoekt naar de klant-ID en URL in de witte lijsten, als deze overeenkomen, wordt er geen actie ondernomen
- zoekt in de Client-regels voor een match, alle toepasselijke regels zijn gegroepeerd op periode, voor elke periode wordt de meest beperkende regel gebruikt
- zoekt in de algemene regels naar een match, als een algemene regel die overeenkomt een gedefinieerde periode heeft die niet aanwezig is in de clientregels, wordt deze algemene regel ook gebruikt
- voor elke overeenkomende regel wordt de snelheidslimietteller verhoogd, als de tellerwaarde groter is dan de regellimiet, wordt het verzoek geblokkeerd
Als het verzoek wordt geblokkeerd, ontvangt de client een sms-reactie zoals deze:
Status Code: 429
Retry-After: 58
Content: API calls quota exceeded! maximum admitted 2 per 1m.
U kunt het antwoord aanpassen door deze opties HttpStatusCode
en QuotaExceededMessage
. Als u uw eigen antwoord wilt implementeren, kunt u ClientRateLimitMiddleware.ReturnQuotaExceededResponse
overschrijven. De Retry-After
wordt uitgedrukt in seconden.
Als het verzoek geen snelheidsbeperking krijgt, wordt de langste periode die is gedefinieerd in de overeenkomende regels gebruikt om de X-Rate-Limit-headers samen te stellen, deze headers worden geïnjecteerd in het antwoord:
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 when the limits resets
Standaard worden geblokkeerde aanvragen geregistreerd met Microsoft.Extensions.Logging.ILogger
, als u uw eigen logboekregistratie wilt implementeren, kunt u ClientRateLimitMiddleware.LogBlockedRequest
overschrijven. De standaard logger zendt de volgende informatie uit wanneer een verzoek snelheidsbeperking krijgt:
info: AspNetCoreRateLimit.ClientRateLimitMiddleware[0]
Request get:/api/values from ClientId client-id-1 has been blocked, quota 2/1m exceeded by 3. Blocked by rule *:/api/value, TraceIdentifier 0HKTLISQQVV9D.
Snelheidslimieten bijwerken tijdens runtime
Bij het opstarten van de toepassing worden de limieten voor de appsettings.json
zijn gedefinieerd in appsettings.json
in de cache geladen door MemoryCacheClientPolicyStore
of DistributedCacheClientPolicyStore
afhankelijk van het type cache-provider dat u gebruikt. U hebt toegang tot de client policy store in een controller en kunt de regels als volgt wijzigen:
public class ClientRateLimitController : Controller { private readonly ClientRateLimitOptions _options; private readonly IClientPolicyStore _clientPolicyStore; public ClientRateLimitController(IOptions<ClientRateLimitOptions> optionsAccessor, IClientPolicyStore clientPolicyStore) { _options = optionsAccessor.Value; _clientPolicyStore = clientPolicyStore; } [HttpGet] public ClientRateLimitPolicy Get() { return _clientPolicyStore.Get($"{_options.ClientPolicyPrefix}_cl-key-1"); } [HttpPost] public void Post() { var id = $"{_options.ClientPolicyPrefix}_cl-key-1"; var clPolicy = _clientPolicyStore.Get(id); clPolicy.Rules.Add(new RateLimitRule { Endpoint = "*/api/testpolicyupdate", Period = "1h", Limit = 100 }); _clientPolicyStore.Set(id, clPolicy); } }
Op deze manier kunt u de limieten van de klantentarieven opslaan in een database en deze na elke start van de app in cache plaatsen.