Limitador de Taxa

O limitador de taxa do webman suporta limitação de taxa por anotações.
Suporta drivers apcu, redis e memory.

Endereço do Código Fonte

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

Instalação

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
    {
        // O limite padrão é por IP, com um intervalo de 1 segundo
        return 'Até 10 requisições por segundo para cada IP';
    }

    #[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
    public function search(): string
    {
        // key: RateLimiter::UID, limita a taxa com base no ID do usuário, exige que session('user.id') não seja nulo
        return 'Até 100 buscas a cada 60 segundos por usuário';
    }

    #[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: 'Cada pessoa pode enviar apenas 1 e-mail por minuto')]
    public function sendMail(): string
    {
        // key: RateLimiter::SID, limita a taxa com base no session_id
        return 'E-mail enviado com sucesso';
    }

    #[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: 'Os cupons de hoje já foram distribuídos, volte amanhã')]
    #[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: 'Cada usuário pode retirar apenas 1 cupom por dia')]
    public function coupon(): string
    {
        // key: 'coupon', aqui 'coupon' é uma chave personalizada, limitando globalmente a taxa com a chave coupon, com um máximo de 100 cupons por dia
        // Também limita a taxa com base no ID do usuário, cada usuário pode retirar apenas 1 cupom por dia
        return 'Cupom enviado com sucesso';
    }

    #[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: 'Cada número de telefone pode receber até 5 mensagens por dia')]
    public function sendSms2(): string
    {
        // Quando a chave é uma variável, pode-se usar a forma [classe, método estático] para obter a chave, por exemplo, [UserController::class, 'getMobile'] chamará o método getMobile() da classe UserController que retornará a chave
        return 'Mensagem enviada com sucesso';
    }

    /**
     * Chave personalizada, obtendo o número de telefone, deve ser um método estático
     * @return string
     */
    public static function getMobile(): string
    {
        return request()->get('mobile');
    }

    #[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: 'Frequência limitada', exception: RuntimeException::class)]
    public function testException(): string
    {
        // A exceção padrão quando o limite é ultrapassado é Webman\RateLimiter\RateLimitException, que pode ser alterada através do parâmetro exception
        return 'ok';
    }

}

Observações

  • O intervalo de tempo padrão é de 1 segundo
  • Pode-se definir o intervalo de tempo usando ttl, por exemplo, ttl:60 significa 60 segundos
  • O limite padrão é por IP (o IP 127.0.0.1 não tem limitação, consulte a seção de configuração abaixo)
  • Inclui limitação por IP, UID (exige que session('user.id') não seja nulo), e SID (com base em session_id)
  • Se você estiver usando um proxy nginx, ao limitar por IP, o cabeçalho X-Forwarded-For deve ser passado, consulte proxy nginx
  • Quando o limite é ultrapassado, a exceção Webman\RateLimiter\RateLimitException será acionada, pode-se personalizar a classe de exceção com exception:xx
  • Quando a exceção é acionada, a mensagem de erro padrão é Too Many Requests, pode-se personalizar a mensagem de erro com message:xx
  • A mensagem de erro padrão também pode ser alterada através de traduções, para Linux, consulte os seguintes comandos
    composer require symfony/translation
    mkdir resource/translations/zh_CN/ -p
    echo "<?php
    return [
    'Too Many Requests' => 'Frequência de requisições limitada'
    ];" > resource/translations/zh_CN/messages.php
    php start.php restart

Interface

Às vezes, os desenvolvedores desejam chamar o limitador diretamente no código, consulte o código abaixo

<?php
namespace app\controller;

use RuntimeException;
use Webman\RateLimiter\Limiter;

class UserController {

    public function sendSms(string $mobile): string
    {
        // Aqui mobile é a chave
        Limiter::check($mobile, 5, 24*60*60, 'Cada número de telefone pode receber até 5 mensagens por dia');
        return 'Mensagem enviada com sucesso';
    }
}

Configuração

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

<?php
return [
    'enable' => true,
    'driver' => 'auto', // auto, apcu, memory, redis
    'stores' => [
        'redis' => [
            'connection' => 'default',
        ]
    ],
    // As requisições desses IPs não têm limitação de frequência (somente é válido quando a chave é RateLimiter::IP)
    'ip_whitelist' => [
        '127.0.0.1',
    ],
];
  • enable: Habilitar limite de taxa
  • driver: Um dos valores auto, apcu, memory, redis, ao usar auto irá escolher automaticamente entre apcu e memory
  • stores: Configuração do redis, connection corresponde à key em config/redis.php
  • ip_whitelist: IPs na lista branca não serão limitados (somente é válido para a chave RateLimiter::IP)

Escolha do driver

memory

  • Introdução
    Não requer a instalação de nenhuma extensão, melhor desempenho.

  • Limitações de Uso
    A limitação de taxa é válida apenas para o processo atual, os dados de limitação de taxa não são compartilhados entre múltiplos processos e não suportam limitação em cluster.

  • Cenários Adequados
    Ambiente de desenvolvimento Windows; negócios que não exigem uma limitação rigorosa; defesa contra ataques de CC.

apcu

  • Instalação da Extensão
    É necessário instalar a extensão apcu e configurar no php.ini

    apc.enabled=1
    apc.enable_cli=1

    Se você não souber a localização do php.ini, pode encontrar usando o comando php --ini

  • Introdução
    Desempenho ligeiramente inferior ao memory, suporta compartilhamento de dados de limitação de taxa entre múltiplos processos.

  • Limitações de Uso
    Não suporta cluster

  • Cenários Adequados
    Qualquer ambiente de desenvolvimento; cenários de limitação de taxa em máquinas simples online; cenários em cluster que não exigem limitação rigorosa; defesa contra ataques de CC.

redis

  • Dependências
    É necessário instalar a extensão redis e o componente Redis, comando de instalação

    composer require -W illuminate/redis illuminate/events
  • Introdução
    Desempenho inferior ao apcu, suporta limitação de taxa precisa tanto em máquinas simples quanto em cluster.

  • Cenários Adequados
    Ambiente de desenvolvimento; ambiente online em máquina única; ambiente em cluster