Limitatore di Velocità
Il limitatore di velocità di webman supporta la limitazione delle richieste tramite annotazioni.
Supporta i driver apcu, redis e memory.
Indirizzo del Codice Sorgente
https://github.com/webman-php/rate-limiter
Installazione
composer require webman/rate-limiter
Utilizzo
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Annotation\RateLimiter;
class UserController
{
#[RateLimiter(limit: 10)]
public function index(): string
{
// Di default, la limitazione è per IP, l'unità di tempo è di 1 secondo
return 'Al massimo 10 richieste per ogni ip al secondo';
}
#[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
public function search(): string
{
// key: RateLimiter::UID, limitazione basata sull'ID utente, richiede che session('user.id') non sia vuota
return 'Ogni utente può fare al massimo 100 ricerche in 60 secondi';
}
#[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: 'Ogni persona può inviare un’email solo 1 volta al minuto')]
public function sendMail(): string
{
// key: RateLimiter::SID, limitazione basata su session_id
return 'Email inviata con successo';
}
#[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'I coupon di oggi sono esauriti, per favore torna domani')]
#[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: 'Ogni utente può ricevere un coupon al giorno')]
public function coupon(): string
{
// key: 'coupon', qui coupon è una chiave personalizzata, limitazione globale con chiave coupon, massimo 100 coupon al giorno
// Limitazione anche basata sull'ID utente, ogni utente può ricevere un coupon al giorno
return 'Coupon inviato con successo';
}
#[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'Ogni numero può ricevere al massimo 5 SMS al giorno')]
public function sendSms2(): string
{
// Quando key è una variabile, puoi usare [classe, metodo statico] per ottenere la chiave, ad esempio [UserController::class, 'getMobile'] chiamerà il metodo getMobile() di UserController per ottenere la chiave
return 'SMS inviato con successo';
}
/**
* Chiave personalizzata per ottenere il numero di telefono, deve essere un metodo statico
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile');
}
#[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: 'Frequenza limitata', exception: RuntimeException::class)]
public function testException(): string
{
// L'eccezione predefinita nel caso di superamento della limitazione è Webman\RateLimiter\RateLimitException, che può essere cambiata tramite il parametro exception
return 'ok';
}
}
Note
- L'intervallo di tempo unitario predefinito è di 1 secondo
- È possibile impostare l'intervallo di tempo unitario tramite ttl, ad esempio
ttl:60
per 60 secondi - La dimensione predefinita della limitazione è per IP (default
127.0.0.1
non ha limitazioni, vedi la parte di configurazione qui sotto) - Limitazioni incorporate per IP, UID (richiede che
session('user.id')
non sia vuota), SID (limitazione in base asession_id
) - Se si utilizza un proxy nginx, per la limitazione per IP occorre passare l'intestazione
X-Forwarded-For
, vedere proxy nginx - Quando si supera il limite, viene sollevata l'eccezione
Webman\RateLimiter\RateLimitException
, è possibile personalizzare la classe di eccezione tramiteexception:xx
- Quando si verifica un'eccezione di superamento del limite, il messaggio di errore predefinito è
Too Many Requests
, è possibile personalizzare il messaggio di errore tramitemessage:xx
- Il messaggio di errore predefinito può anche essere modificato tramite traduzione multilingue, per Linux fare riferimento ai seguenti comandi
composer require symfony/translation mkdir resource/translations/zh_CN/ -p echo "<?php return [ 'Too Many Requests' => 'Richiesta frequenza limitata' ];" > resource/translations/zh_CN/messages.php php start.php restart
Interfaccia
A volte gli sviluppatori vogliono chiamare direttamente il limitatore nel codice, vedere il seguente codice
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Limiter;
class UserController {
public function sendSms(string $mobile): string
{
// Qui mobile è usato come chiave
Limiter::check($mobile, 5, 24*60*60, 'Ogni numero può ricevere al massimo 5 SMS al giorno');
return 'SMS inviato con successo';
}
}
Configurazione
config/plugin/webman/rate-limiter/app.php
<?php
return [
'enable' => true,
'driver' => 'auto', // auto, apcu, memory, redis
'stores' => [
'redis' => [
'connection' => 'default',
]
],
// Questi IP non vengono limitati (efficace solo quando la chiave è RateLimiter::IP)
'ip_whitelist' => [
'127.0.0.1',
],
];
- enable: abilitare la limitazione
- driver: uno dei valori
auto
apcu
memory
redis
, usandoauto
seleziona automaticamente uno traapcu
ememory
- stores: configurazione per
redis
,connection
corrisponde alla chiave inconfig/redis.php
- ip_whitelist: gli IP in whitelist non saranno soggetti a limitazione (efficace solo quando la chiave è
RateLimiter::IP
)
Scelta del driver
memory
-
Introduzione
Non richiede l'installazione di alcuna estensione, offre le migliori performance. -
Limiti di utilizzo
La limitazione è valida solo per il processo corrente, i dati di limitazione non sono condivisi tra più processi e non supporta la limitazione in cluster. -
Scenari di applicazione
Ambiente di sviluppo Windows; attività che non richiede limitazione rigorosa; difesa contro attacchi CC.
apcu
-
Installazione dell'estensione
È necessario installare l'estensione apcu e configurare il php.iniapc.enabled=1 apc.enable_cli=1
Se non sai dove si trova php.ini, puoi utilizzare il comando
php --ini
per trovarne la posizione -
Introduzione
Le performance sono leggermente inferiori rispetto a memory, supporta la condivisione dei dati di limitazione tra più processi. -
Limiti di utilizzo
Non supporta il clustering -
Scenari di applicazione
Qualsiasi ambiente di sviluppo; scenari di limitazione in produzione su macchina singola; scenari di clustering che non richiedono limitazione rigorosa; difesa contro attacchi CC.
redis
-
Dipendenze
È necessario installare l'estensione redis e installare il componente Redis, comando di installazionecomposer require -W illuminate/redis illuminate/events
-
Introduzione
Le performance sono inferiori a quelle di apcu, supporta limitazioni precise sia su macchina singola che in cluster. -
Scenari di applicazione
Ambiente di sviluppo; ambiente di produzione su singola macchina; ambiente di cluster