tobento/app-rate-limiter

应用速率限制支持。

1.0.1 2024-06-04 16:14 UTC

This package is auto-updated.

Last update: 2024-09-04 16:54:51 UTC


README

使用默认实现 Symfony - Rate Limiter 组件的应用速率限制支持。

目录

入门

运行此命令以安装应用速率限制项目的最新版本。

composer require tobento/app-rate-limiter

需求

  • PHP 8.0 或更高版本

文档

应用

如果您正在使用骨架,请查看 App Skeleton

您还可以查看 App 了解更多关于应用程序的信息。

速率限制启动

速率限制启动执行以下操作

  • 安装和加载速率限制配置文件
  • 实现速率限制接口
use Tobento\App\AppFactory;
use Tobento\App\RateLimiter\RateLimiterCreatorInterface;
use Tobento\App\RateLimiter\RegistriesInterface;
use Tobento\App\RateLimiter\FingerprintInterface;

// Create the app
$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\RateLimiter\Boot\RateLimiter::class);
$app->booting();

// Implemented interfaces:
$limiterCreator = $app->get(RateLimiterCreatorInterface::class);
$registries = $app->get(RegistriesInterface::class);
$fingerprint = $app->get(FingerprintInterface::class);

// Run the app
$app->run();

速率限制配置

速率限制配置位于默认应用程序骨架配置位置的 app/config/rate_limiter.php 文件中,您可以在此处指定应用程序的命名速率限制器。

基本用法

使用速率限制创建器

启动速率限制后,将其注入任何服务或控制器。您可以考虑同时启动 App Http - Routing Boot 以获取 HTTP 和路由支持。

use Tobento\App\AppFactory;
use Tobento\App\RateLimiter\RateLimiterCreatorInterface;
use Tobento\App\RateLimiter\Symfony\Registry\SlidingWindow;
use Tobento\App\Http\Exception\TooManyRequestsException;

$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\Http\Boot\ErrorHandler::class);
$app->boot(\Tobento\App\Http\Boot\Routing::class);
$app->boot(\Tobento\App\RateLimiter\Boot\RateLimiter::class);
$app->booting();

// Routes:
$app->route('POST', 'login', function(ServerRequestInterface $request, RateLimiterCreatorInterface $limiterCreator) {
    // create a rate limiter:
    $limiter = $limiterCreator->createFromRegistry(
        // a unique identifier of the client:
        id: $request->getServerParams()['REMOTE_ADDR'] ?? null,
        // define the rate limiter to use:
        registry: new SlidingWindow(limit: 5, interval: '5 minutes'),
    );

    // next hit the limiter and check if attempts exceeded:
    if ($limiter->hit()->isAttemptsExceeded()) {
        throw new TooManyRequestsException(
            retryAfter: $limiter->availableIn(),
            message: sprintf('Too Many Requests. Please retry after %d seconds.', $limiter->availableIn()),
            headers: [
                'X-RateLimit-Limit' => $limiter->maxAttempts(),
                'X-RateLimit-Remaining' => $limiter->remainingAttempts(),
                'X-RateLimit-Reset' => $limiter->availableAt()->getTimestamp(),
            ],
        );
    }

    // you may reset the attempts:
    // $limiter->reset();
    
    return 'response';
});

// Run the app:
$app->run();

查看 可用的速率限制注册表 了解其可用的限制器注册表。

使用 RateLimitRequests 中间件

使用 RateLimitRequests::class 中间件轻松限制路由。

use Tobento\App\AppFactory;
use Tobento\App\RateLimiter\Middleware\RateLimitRequests;
use Tobento\App\RateLimiter\Symfony\Registry\SlidingWindow;
use Tobento\App\Http\Exception\TooManyRequestsException;

$app = (new AppFactory())->createApp();

// Add directories:
$app->dirs()
    ->dir(realpath(__DIR__.'/../'), 'root')
    ->dir(realpath(__DIR__.'/../app/'), 'app')
    ->dir($app->dir('app').'config', 'config', group: 'config')
    ->dir($app->dir('root').'public', 'public')
    ->dir($app->dir('root').'vendor', 'vendor');

// Adding boots:
$app->boot(\Tobento\App\Http\Boot\ErrorHandler::class);
$app->boot(\Tobento\App\Http\Boot\Routing::class);
$app->boot(\Tobento\App\Http\Boot\RequesterResponser::class); // for redirection support
$app->boot(\Tobento\App\RateLimiter\Boot\RateLimiter::class);
$app->booting();

// Routes:
$app->route('POST', 'login', function() {
    // being rate limited!
    return 'response';
})->middleware([
    RateLimitRequests::class,
    
    // define the rate limiter to use:
    'registry' => new SlidingWindow(limit: 5, interval: '5 minutes'),
    
    // or by named rate limiter:
    //'registry' => 'login',
]);

$app->route('POST', 'register', function() {
    // being rate limited!
    return 'response';
})->middleware([
    RateLimitRequests::class,
    'registry' => new SlidingWindow(limit: 5, interval: '5 minutes'),
    
    // You may specify a redirect uri or route
    // which will redirect instead of throwing a TooManyRequestsException:
    'redirectUri' => '/register',
    'redirectRoute' => 'register',
    
    // You may specify a redirect message to be flashed.
    // The :seconds parameter value will be set by the middleware.
    'message' => 'Too many attempts. Please retry after :seconds seconds.',
    'messageLevel' => 'error', // default
    'messageKey' => 'email', // or null default
]);

// Run the app:
$app->run();

可用的速率限制注册表

工厂

可以使用 Factory 注册表从任何工厂创建速率限制器

use Tobento\App\RateLimiter\Registry\Factory;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new Factory(
        factory: RateLimiterFactory::class,
        config: [
            'policy' => 'sliding_window',
            'limit' => 5,
            'interval' => '5 Minutes',
        ],
    ),
);

固定窗口

FixedWindow 注册表创建 Symfony 固定窗口速率限制器

use Tobento\App\RateLimiter\Symfony\Registry\FixedWindow;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new FixedWindow(
        limit: 100,
        interval: '5 Minutes',
        
        // you may specify an id prefix:
        id: 'api',
        
        // you may change the storage used:
        storage: 'inmemory', // 'cache' is default
        
        // you may change the cache used if using the cache storage:
        cache: 'api-ratelimiter', // 'ratelimiter' is default
    ),
);

您可以在 App Cache - Config 中定义 ratelimiter 名称(默认)或 api-ratelimiter(自定义)的缓存,否则默认使用主缓存。

命名

Named 注册表可用于从命名速率限制器创建速率限制器

use Tobento\App\RateLimiter\Registry\Named;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new Named('api'),
);

请查看 注册命名速率限制器 部分以了解更多信息。

无限制

NoLimit 注册表创建 Symfony 无限制速率限制器

use Tobento\App\RateLimiter\Symfony\Registry\NoLimit;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new NoLimit(),
);

滑动窗口

SlidingWindow 注册表创建 Symfony 滑动窗口速率限制器

use Tobento\App\RateLimiter\Symfony\Registry\SlidingWindow;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new SlidingWindow(
        limit: 100,
        interval: '5 Minutes',
        
        // you may specify an id prefix:
        id: 'api',
        
        // you may change the storage used:
        storage: 'inmemory', // 'cache' is default
        
        // you may change the cache used if using the cache storage:
        cache: 'api-ratelimiter', // 'ratelimiter' is default
    ),
);

您可以在 App Cache - Config 中定义 ratelimiter 名称(默认)或 api-ratelimiter(自定义)的缓存,否则默认使用主缓存。

令牌桶

TokenBucket 注册表创建 Symfony 令牌桶速率限制器

use Tobento\App\RateLimiter\Symfony\Registry\TokenBucket;
use Tobento\App\RateLimiter\Symfony\RateLimiterFactory;

$limiter = $limiterCreator->createFromRegistry(
    id: 'a-unique-identifier',
    registry: new TokenBucket(
        limit: 5000,
        rateAmount: 500,
        rateInterval: '60 Minutes',
        
        // you may specify an id prefix:
        id: 'api',
        
        // you may change the storage used:
        storage: 'inmemory', // 'cache' is default
        
        // you may change the cache used if using the cache storage:
        cache: 'api-ratelimiter', // 'ratelimiter' is default
    ),
);

您可以在 App Cache - Config 中定义 ratelimiter 名称(默认)或 api-ratelimiter(自定义)的缓存,否则默认使用主缓存。

注册命名速率限制器

通过配置文件注册命名速率限制器

您可以在配置文件 app/config/rate_limiter.php 中注册命名速率限制器。

return [
    // ...
    'limiters' => [
        'api' => new TokenBucket(limit: 10, rateAmount: 5, rateInterval: '5 Minutes'),
        'login' => new FixedWindow(limit: 2, interval: '1 Minutes'),
    ],
];

通过引导注册命名速率限制器

use Tobento\App\Boot;
use Tobento\App\RateLimiter\Boot\RateLimiter;
use Tobento\App\RateLimiter\RegistriesInterface;
use Tobento\App\RateLimiter\Symfony\Registry\FixedWindow;

class RateLimitersBoot extends Boot
{
    public const BOOT = [
        // you may ensure the rate limiter boot.
        RateLimiter::class,
    ];
    
    public function boot()
    {
        // you may use the app on method to add only if requested:
        $app->on(
            RegistriesInterface::class,
            static function(RegistriesInterface $registries) {
                $registries->add(
                    name: 'api',
                    registry: new FixedWindow(limit: 2, interval: '1 Minutes'),
                );
            }
        );
    }
}

事件

可用事件

支持的事件

简单地,安装App Event捆绑包。

信用