Limiteur de Taux

Le limiteur de taux de webman prend en charge la limitation par annotations.
Il prend en charge les pilotes apcu, redis et memory.

Adresse du Code Source

https://github.com/webman-php/rate-limiter

Installation

composer require webman/rate-limiter

Utilisation

<?php
namespace app\controller;

use RuntimeException;
use Webman\RateLimiter\Annotation\RateLimiter;

class UserController
{

    #[RateLimiter(limit: 10)]
    public function index(): string
    {
        // Par défaut, la limitation est basée sur l'IP, la durée par défaut est de 1 seconde
        return '10 requêtes maximum par seconde pour chaque IP';
    }

    #[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
    public function search(): string
    {
        // key: RateLimiter::UID, limitation par ID utilisateur, session('user.id') ne doit pas être vide
        return '100 recherches maximum par utilisateur toutes les 60 secondes';
    }

    #[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: 'Chaque personne peut envoyer un e-mail une fois par minute')]
    public function sendMail(): string
    {
        // key: RateLimiter::SID, limitation basée sur session_id
        return 'E-mail envoyé avec succès';
    }

    #[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'Les coupons d\'aujourd\'hui ont tous été envoyés, revenez demain')]
    #[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: 'Chaque utilisateur ne peut réclamer qu\'un coupon par jour')]
    public function coupon(): string
    {
        // key: 'coupon', ici coupon est une clé personnalisée, limitant le nombre de coupons à 100 par jour
        // Dans le même temps, limitation par ID utilisateur, chaque utilisateur ne peut réclamer qu'un coupon par jour
        return 'Coupon envoyé avec succès';
    }

    #[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'Chaque numéro de portable peut recevoir au maximum 5 SMS par jour')]
    public function sendSms2(): string
    {
        // Lorsque la clé est une variable, on peut utiliser [classe, méthode statique] pour obtenir la clé, par exemple [UserController::class, 'getMobile'] renvoie la valeur de la méthode getMobile() de UserController
        return 'SMS envoyé avec succès';
    }

    /**
     * Clé personnalisée, obtient le numéro de portable, doit être une méthode statique
     * @return string
     */
    public static function getMobile(): string
    {
        return request()->get('mobile');
    }

    #[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: 'Limite de fréquence atteinte', exception: RuntimeException::class)]
    public function testException(): string
    {
        // Exception par défaut lors du dépassement est Webman\RateLimiter\RateLimitException, peut être changée par le paramètre exception
        return 'ok';
    }

}

Remarques

  • La durée par défaut est de 1 seconde
  • Vous pouvez définir une durée via ttl, par exemple ttl:60 pour 60 secondes
  • La dimension de limitation par défaut est basée sur l'IP (par défaut 127.0.0.1 n'a pas de limitation, voir la configuration ci-dessous)
  • Prise en charge des limitations basées sur l'IP, UID (requiert que session('user.id') ne soit pas vide), SID (basé sur session_id)
  • Si vous utilisez un proxy nginx, pour la limitation IP, vous devez transmettre l'en-tête X-Forwarded-For, voir proxy nginx
  • Lorsqu'une limitation est atteinte, cela déclenche l'exception Webman\RateLimiter\RateLimitException, vous pouvez personnaliser la classe d'exception avec exception:xx
  • Lorsqu'une limite est atteinte, le message d'erreur par défaut est Too Many Requests, il peut être personnalisé avec message:xx
  • Le message d'erreur par défaut peut également être modifié via traduction, sous Linux, consultez les commandes suivantes
    composer require symfony/translation
    mkdir resource/translations/zh_CN/ -p
    echo "<?php
    return [
    'Too Many Requests' => 'Fréquence de demande limitée'
    ];" > resource/translations/zh_CN/messages.php
    php start.php restart

Interface

Parfois, les développeurs souhaitent appeler directement le limiteur dans le code, voir l'exemple ci-dessous

<?php
namespace app\controller;

use RuntimeException;
use Webman\RateLimiter\Limiter;

class UserController {

    public function sendSms(string $mobile): string
    {
        // ici mobile est utilisé comme clé
        Limiter::check($mobile, 5, 24*60*60, 'Chaque numéro de portable peut recevoir au maximum 5 SMS par jour');
        return 'SMS envoyé avec succès';
    }
}

Configuration

config/plugin/webman/rate-limiter/app.php

<?php
return [
    'enable' => true,
    'driver' => 'auto', // auto, apcu, memory, redis
    'stores' => [
        'redis' => [
            'connection' => 'default',
        ]
    ],
    // Ces IP ne subissent pas de limitation de fréquence (valide uniquement quand la clé est RateLimiter::IP)
    'ip_whitelist' => [
        '127.0.0.1',
    ],
];
  • enable: Activer la limitation
  • driver: Une valeur parmi auto apcu memory redis, en utilisant auto, il choisira automatiquement entre apcu et memory
  • stores: Configuration redis, connection correspond à la key dans config/redis.php
  • ip_whitelist: Les IP de la liste blanche ne seront pas soumises à la limitation (valide uniquement lorsque la clé est RateLimiter::IP)

Choix du pilote

memory

  • Introduction
    Aucun module à installer, meilleures performances.

  • Limitations d'utilisation
    La limitation ne s'applique qu'au processus actuel, les données de limitation ne sont pas partagées entre plusieurs processus, et ne prend pas en charge la limitation en cluster.

  • Scénarios d'application
    Environnement de développement Windows ; affaires sans limitation stricte ; défense contre les attaques CC.

apcu

  • Installation de l'extension
    L'extension apcu doit être installée, et dans php.ini doit être réglé

    apc.enabled=1
    apc.enable_cli=1

    Si vous ne savez pas où se trouve le fichier php.ini, vous pouvez le trouver en exécutant la commande php --ini

  • Introduction
    Performance légèrement inférieure à celle de memory, prend en charge le partage des données de limitation entre plusieurs processus.

  • Limitations d'utilisation
    Ne prend pas en charge les clusters

  • Scénarios d'application
    Tout environnement de développement ; scénarios de limitation sur une machine unique en ligne ; scénarios de clusters sans limitation stricte ; défense contre les attaques CC.

redis

  • Dépendances
    L'extension redis doit être installée, et le composant Redis doit être installé, commande d'installation

    composer require -W illuminate/redis illuminate/events
  • Introduction
    Performance inférieure à apcu, prend en charge la limitation précise pour une seule machine et aussi pour des clusters

  • Scénarios d'application
    Environnement de développement ; environnement de machine unique en ligne ; environnement de cluster