Rate Limiter
webman Rate Limiter mit Annotation-basierter Begrenzung.
Unterstützt apcu-, redis- und memory-Treiber.
Quellcode
https://github.com/webman-php/limiter
Installation
composer require webman/limiter
Verwendung
<?php
namespace app\controller;
use RuntimeException;
use support\limiter\annotation\Limit;
class UserController
{
#[Limit(limit: 10)]
public function index(): string
{
// Standard ist IP-basierte Begrenzung, Standard-Zeitfenster 1 Sekunde
return 'Maximal 10 Anfragen pro IP pro Sekunde';
}
#[Limit(limit: 100, ttl: 60, key: Limit::UID)]
public function search(): string
{
// key: Limit::UID, Begrenzung nach Benutzer-ID, erfordert session('user.id') nicht leer
return 'Maximal 100 Suchen pro Benutzer pro 60 Sekunden';
}
#[Limit(limit: 1, ttl: 60, key: Limit::SID, message: 'Nur 1 E-Mail pro Person pro Minute')]
public function sendMail(): string
{
// key: Limit::SID, Begrenzung nach session_id
return 'E-Mail erfolgreich gesendet';
}
#[Limit(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'Heutige Gutscheine ausverkauft, bitte morgen erneut versuchen')]
#[Limit(limit: 1, ttl: 24*60*60, key: Limit::UID, message: 'Jeder Benutzer kann nur einen Gutschein pro Tag einlösen')]
public function coupon(): string
{
// key: 'coupon', benutzerdefinierter Key für globale Begrenzung, max. 100 Gutscheine pro Tag
// Auch Begrenzung nach Benutzer-ID, jeder Benutzer nur einen Gutschein pro Tag
return 'Gutschein erfolgreich gesendet';
}
#[Limit(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'Maximal 5 SMS pro Telefonnummer pro Tag')]
public function sendSms2(): string
{
// Bei variablem Key: [Klasse, statische_Methode], z.B. [UserController::class, 'getMobile'] verwendet Rückgabewert von UserController::getMobile() als Key
return 'SMS erfolgreich gesendet';
}
/**
* Benutzerdefinierter Key, Telefonnummer abrufen, muss statische Methode sein
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile');
}
#[Limit(limit: 1, ttl: 10, key: Limit::IP, message: 'Rate begrenzt', exception: RuntimeException::class)]
public function testException(): string
{
// Standard-Exception bei Überschreitung: support\limiter\RateLimitException, änderbar über exception-Parameter
return 'ok';
}
}
Hinweise
- Verwendet Fixed-Window-Algorithmus
- Standard-ttl-Zeitfenster ist 1 Sekunde
- Zeitfenster über ttl setzen, z.B.
ttl:60für 60 Sekunden - Standard-Begrenzungsdimension ist IP (Standard
127.0.0.1nicht begrenzt, siehe Konfiguration unten) - Integriert: IP-, UID- (erfordert
session('user.id')nicht leer) und SID-Begrenzung (nachsession_id) - Bei nginx-Proxy
X-Forwarded-For-Header für IP-Begrenzung übergeben, siehe nginx Proxy - Löst
support\limiter\RateLimitExceptionbei Überschreitung aus, benutzerdefinierte Exception-Klasse überexception:xx - Standard-Fehlermeldung bei Überschreitung ist
Too Many Requests, benutzerdefinierte Meldung übermessage:xx - Standard-Fehlermeldung auch über Übersetzung änderbar, Linux-Referenz:
composer require symfony/translation
mkdir resource/translations/zh_CN/ -p
echo "<?php
return [
'Too Many Requests' => '请求频率受限'
];" > resource/translations/zh_CN/messages.php
php start.php restart
API
Manchmal möchten Entwickler den Rate Limiter direkt im Code aufrufen, siehe folgendes Beispiel:
<?php
namespace app\controller;
use RuntimeException;
use support\limiter\Limiter;
class UserController {
public function sendSms(string $mobile): string
{
// mobile wird hier als Key verwendet
Limiter::check($mobile, 5, 24*60*60, 'Maximal 5 SMS pro Telefonnummer pro Tag');
return 'SMS erfolgreich gesendet';
}
}
Konfiguration
config/plugin/webman/limiter/app.php
<?php
use support\limiter\RateLimitException;
return [
'enable' => true,
'driver' => 'auto', // auto, apcu, memory, redis
'stores' => [
'redis' => [
'connection' => 'default',
]
],
// Diese IPs werden nicht begrenzt (nur wirksam wenn key Limit::IP ist)
'ip_whitelist' => [
'127.0.0.1',
],
'exception' => RateLimitException::class
];
- enable: Rate Limiting aktivieren
- driver: Einer von
auto,apcu,memory,redis;autowählt automatisch zwischenapcu(bevorzugt) undmemory - stores: Redis-Konfiguration,
connectionentspricht dem Key inconfig/redis.php - ip_whitelist: Whitelist-IPs werden nicht begrenzt (nur wirksam wenn key
Limit::IPist)
Driver-Auswahl
memory
-
Einführung
Keine Erweiterungen nötig, beste Leistung. -
Einschränkungen
Begrenzung nur für aktuellen Prozess, keine Datenfreigabe zwischen Prozessen, Cluster-Begrenzung nicht unterstützt. -
Anwendungsfälle
Windows-Entwicklungsumgebung; Geschäftsszenarien ohne strenge Begrenzung; CC-Angriffsabwehr.
apcu
- Erweiterungsinstallation
apcu-Erweiterung erforderlich, php.ini-Einstellungen:
apc.enabled=1
apc.enable_cli=1
php.ini-Pfad mit php --ini ermitteln
-
Einführung
Sehr gute Leistung, unterstützt Multi-Prozess-Datenfreigabe. -
Einschränkungen
Cluster nicht unterstützt -
Anwendungsfälle
Jede Entwicklungsumgebung; Produktions-Einzel-Server-Begrenzung; Cluster ohne strenge Begrenzung; CC-Angriffsabwehr.
redis
- Abhängigkeiten
redis-Erweiterung und Redis-Komponente erforderlich, Installation:
composer require -W webman/redis illuminate/events
-
Einführung
Geringere Leistung als apcu, unterstützt präzise Begrenzung für Einzel-Server und Cluster -
Anwendungsfälle
Entwicklungsumgebung; Produktions-Einzel-Server; Cluster-Umgebung