Limitador de tasa

El limitador de tasa de webman admite limitación de tasa a través de anotaciones.
Admite controladores de apcu, redis y memoria.

Dirección del código fuente

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

Instalación

composer require webman/rate-limiter

Uso

<?php
namespace app\controller;

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

class UserController
{

    #[RateLimiter(limit: 10)]
    public function index(): string
    {
        // Por defecto, la limitación se basa en la IP, y el tiempo unitario predeterminado es 1 segundo
        return 'Máximo 10 solicitudes por segundo por IP';
    }

    #[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
    public function search(): string
    {
        // key: RateLimiter::UID, se limita por ID de usuario, se requiere que session('user.id') no esté vacío
        return 'Máximo 100 búsquedas por usuario cada 60 segundos';
    }

    #[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: 'Cada persona solo puede enviar 1 correo electrónico por minuto')]
    public function sendMail(): string
    {
        // key: RateLimiter::SID, se limita por session_id
        return 'Correo enviado con éxito';
    }

    #[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'Las cupones de hoy ya se han agotado, por favor vuelva mañana')]
    #[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: 'Cada usuario solo puede canjear un cupón por día')]
    public function coupon(): string
    {
        // key: 'coupon', aquí coupon es una clave personalizada, es decir, se limita globalmente por la clave coupon, máximo 100 cupones por día
        // Al mismo tiempo, se limita por ID de usuario, cada usuario solo puede canjear un cupón por día
        return 'Cupón enviado con éxito';
    }

    #[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'Cada número de teléfono puede recibir un máximo de 5 mensajes de texto al día')]
    public function sendSms2(): string
    {
        // Cuando la clave es una variable, se puede utilizar la forma [clase, método estático] para obtener la clave, por ejemplo, [UserController::class, 'getMobile'] llamará al método getMobile() de UserController y usará su valor de retorno como clave
        return 'Mensaje de texto enviado con éxito';
    }

    /**
     * Clave personalizada, obtener número de teléfono, debe ser un método estático
     * @return string
     */
    public static function getMobile(): string
    {
        return request()->get('mobile');
    }

    #[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: 'Frecuencia limitada', exception: RuntimeException::class)]
    public function testException(): string
    {
        // La excepción predeterminada cuando se supera el límite es Webman\RateLimiter\RateLimitException, se puede cambiar a través del parámetro exception
        return 'ok';
    }

}

Descripción

  • El intervalo de tiempo predeterminado es de 1 segundo
  • Se puede establecer el intervalo de tiempo a través de ttl, por ejemplo, ttl:60 equivale a 60 segundos
  • La dimensión de limitación predeterminada es la limitación por IP (por defecto 127.0.0.1 no tiene límite, consulte la sección de configuración a continuación)
  • Limitación incorporada por IP, limitación por UID (se requiere que session('user.id') no esté vacío) y limitación por SID (limitación según session_id)
  • Si se usa un proxy nginx, al limitar por IP se debe pasar el encabezado X-Forwarded-For, consulte proxy de nginx
  • Al superar el límite, se activará la excepción Webman\RateLimiter\RateLimitException, se puede personalizar la clase de excepción a través de exception:xx
  • Cuando se activa la excepción por exceder el límite, el mensaje de error predeterminado es Too Many Requests, se puede personalizar el mensaje de error a través de message:xx
  • El mensaje de error predeterminado también se puede modificar a través de traducción multilenguaje, en Linux consulte los siguientes comandos
    composer require symfony/translation
    mkdir resource/translations/zh_CN/ -p
    echo "<?php
    return [
    'Too Many Requests' => 'Frecuencia de solicitudes limitada'
    ];" > resource/translations/zh_CN/messages.php
    php start.php restart

Interfaz

A veces los desarrolladores quieren llamar directamente al limitador de tasa en el código, consulte el siguiente código

<?php
namespace app\controller;

use RuntimeException;
use Webman\RateLimiter\Limiter;

class UserController {

    public function sendSms(string $mobile): string
    {
        // Aquí mobile se usa como clave
        Limiter::check($mobile, 5, 24*60*60, 'Cada número de teléfono puede recibir un máximo de 5 mensajes de texto al día');
        return 'Mensaje de texto enviado con éxito';
    }
}

Configuración

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

<?php
return [
    'enable' => true,
    'driver' => 'auto', // auto, apcu, memory, redis
    'stores' => [
        'redis' => [
            'connection' => 'default',
        ]
    ],
    // Las solicitudes de estas IP no tienen limitación de frecuencia (solamente cuando la clave es RateLimiter::IP es efectivo)
    'ip_whitelist' => [
        '127.0.0.1',
    ],
];
  • enable: Si se habilita la limitación de tasa
  • driver: Uno de los valores auto, apcu, memory, redis, cuando se usa auto, elegirá automáticamente uno entre apcu y memory
  • stores: Configuración para redis, connection corresponde a la key en config/redis.php
  • ip_whitelist: Las IP de la lista blanca no serán limitadas (solo es efectivo cuando la clave es RateLimiter::IP)

Elección de controlador

memory

  • Introducción
    No requiere la instalación de ninguna extensión, tiene mejor rendimiento.

  • Restricciones de uso
    La limitación sólo es efectiva para el proceso actual, no se comparten los datos de limitación entre múltiples procesos y tampoco soporta la limitación en clúster.

  • Escenario adecuado
    Entorno de desarrollo en Windows; negocios que no requieren una limitación estricta; resistencia a ataques CC.

apcu

  • Instalación de la extensión
    Necesita instalar la extensión apcu y configurar en php.ini

    apc.enabled=1
    apc.enable_cli=1

    Si no sabe dónde se encuentra php.ini, puede buscar la ubicación de php.ini utilizando el comando php --ini.

  • Introducción
    Rendimiento ligeramente inferior a memory, admite la compartición de datos de limitación entre procesos.

  • Restricciones de uso
    No soporta clúster.

  • Escenario adecuado
    Cualquier entorno de desarrollo; escenarios de limitación en un solo servidor en producción; escenarios de clúster que no requieren limitación estricta; resistencia a ataques CC.

redis

  • Dependencias
    Necesita instalar la extensión redis y el componente Redis, con el siguiente comando de instalación

    composer require -W illuminate/redis illuminate/events
  • Introducción
    Rendimiento inferior al de apcu, admite limitación precisa tanto en un solo servidor como en clúster.

  • Escenario adecuado
    Entorno de desarrollo; entorno en un solo servidor en producción; entorno de clúster.