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 a session_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 tramite exception:xx
  • Quando si verifica un'eccezione di superamento del limite, il messaggio di errore predefinito è Too Many Requests, è possibile personalizzare il messaggio di errore tramite message: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, usando auto seleziona automaticamente uno tra apcu e memory
  • stores: configurazione per redis, connection corrisponde alla chiave in config/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.ini

    apc.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 installazione

    composer 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