tobento / app-rate-limiter
应用速率限制支持。
Requires
- php: >=8.0
- symfony/rate-limiter: ^6.0
- tobento/app: ^1.0.7
- tobento/app-cache: ^1.0.1
- tobento/app-http: ^1.0 || ^1.1
- tobento/app-migration: ^1.0
Requires (Dev)
- nyholm/psr7: ^1.4
- phpunit/phpunit: ^9.5
- tobento/app-event: ^1.0.1
- tobento/app-user: ^1.0
- tobento/service-filesystem: ^1.0.5
- vimeo/psalm: ^4.0
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捆绑包。