レートリミッター
Webmanレートリミッターは、アノテーションによるレートリミットをサポートしています。
APCu、Redis、Memoryドライバーに対応しています。
ソースコードのアドレス
https://github.com/webman-php/rate-limiter
インストール
composer require webman/rate-limiter
使用方法
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Annotation\RateLimiter;
class UserController
{
#[RateLimiter(limit: 10)]
public function index(): string
{
// デフォルトはIPでのレートリミット、デフォルトの単位時間は1秒です
return '各IPは毎秒最大10件のリクエストを送信できます';
}
#[RateLimiter(limit: 100, ttl: 60, key: RateLimiter::UID)]
public function search(): string
{
// key: RateLimiter::UID、ユーザーIDを基準にレートリミットします。要求はsession('user.id')が空でない必要があります
return '各ユーザーは60秒間に最大100回検索できます';
}
#[RateLimiter(limit: 1, ttl: 60, key: RateLimiter::SID, message: '各人は1分間に1回のみメールを送信できます')]
public function sendMail(): string
{
// key: RateLimiter::SID、 session_idを基準にレートリミットします
return 'メールは正常に送信されました';
}
#[RateLimiter(limit: 100, ttl: 24*60*60, key: 'coupon', message: '今日のクーポンはすでに配布済みです。明日再度お越しください')]
#[RateLimiter(limit: 1, ttl: 24*60*60, key: RateLimiter::UID, message: '各ユーザーは1日1回のみクーポンを受け取れます')]
public function coupon(): string
{
// key: 'coupon'、ここでcouponはカスタムキーであり、全体でcouponをキーとしてレートリミットします。最大で1日あたり100枚のクーポンを配布します
// 同時にユーザーIDを基準にレートリミットしており、各ユーザーは1日1回のみクーポンを受け取れます
return 'クーポンは正常に配布されました';
}
#[RateLimiter(limit: 5, ttl: 24*60*60, key: [UserController::class, 'getMobile'], message: '各電話番号は1日に最大5件のSMSを受信できます')]
public function sendSms2(): string
{
// keyが変数の場合、[クラス, 静的メソッド]の方法でkeyを取得できます。例えば[UserController::class, 'getMobile']はUserControllerのgetMobile()メソッドを呼び出し、その戻り値をkeyとして使用します
return 'SMSは正常に送信されました';
}
/**
* カスタムキーとして電話番号を取得します。静的メソッドでなければなりません
* @return string
*/
public static function getMobile(): string
{
return request()->get('mobile');
}
#[RateLimiter(limit: 1, ttl: 10, key: RateLimiter::IP, message: '頻度制限', exception: RuntimeException::class)]
public function testException(): string
{
// 超過した場合、デフォルトの例外はWebman\RateLimiter\RateLimitExceptionです。exceptionパラメータで変更できます
return 'ok';
}
}
説明
- デフォルトの単位時間間隔は1秒です。
- ttlを使用して単位時間間隔を設定できます。例えば
ttl:60
は60秒です。 - デフォルトのレートリミットの基準はIPリミットです(デフォルトでは
127.0.0.1
はレートリミットされません。以下の設定部分を参照してください)。 - 内蔵のIPリミット、UIDリミット(
session('user.id')
が空でない必要があります)、SIDリミット(session_id
に基づくリミット)があります。 - Nginxプロキシを使用している場合、IPリミット時には
X-Forwarded-For
ヘッダーを渡す必要があります。詳しくはnginx代理を参照してください。 - 超過時には
Webman\RateLimiter\RateLimitException
例外が発生し、exception:xx
を使用してカスタム例外クラスを指定できます。 - 超過時のエラーメッセージはデフォルトで
Too Many Requests
ですが、message:xx
を使用してカスタマイズ可能です。 - デフォルトのエラーメッセージは多言語を通じて変更可能です。Linuxの場合、以下のコマンドを参考にしてください。
composer require symfony/translation mkdir resource/translations/zh_CN/ -p echo "<?php return [ 'Too Many Requests' => 'リクエスト頻度が制限されています' ];" > resource/translations/zh_CN/messages.php php start.php restart
インターフェース
時折、開発者はコード内で直接レートリミッターを呼び出したいことがあります。以下のコードを参考にしてください。
<?php
namespace app\controller;
use RuntimeException;
use Webman\RateLimiter\Limiter;
class UserController {
public function sendSms(string $mobile): string
{
// ここでmobileがkeyとして使用されます
Limiter::check($mobile, 5, 24*60*60, '各電話番号は1日に最大5件のSMSを受信できます');
return 'SMSは正常に送信されました';
}
}
設定
config/plugin/webman/rate-limiter/app.php
<?php
return [
'enable' => true,
'driver' => 'auto', // auto, apcu, memory, redis
'stores' => [
'redis' => [
'connection' => 'default',
]
],
// これらのIPからのリクエストは頻度制限されません(keyがRateLimiter::IPのときのみ有効)
'ip_whitelist' => [
'127.0.0.1',
],
];
- enable: レートリミッターを有効にするかどうか
- driver:
auto
、apcu
、memory
、redis
のいずれかの値を指定します。auto
を使用する場合は、自動的にapcu
またはmemory
のいずれかを選択します。 - stores:
redis
の設定。connection
はconfig/redis.php
内の対応するkey
に対応します。 - ip_whitelist: ホワイトリスト内のIPはレートリミットされません(keyが
RateLimiter::IP
の時のみ有効)。
ドライバーの選択
memory
-
紹介
何の拡張もインストールする必要がなく、最高のパフォーマンスを発揮します。 -
使用制限
レートリミットは現在のプロセスにのみ有効であり、複数のプロセス間でレートリミットデータは共有されません。また、クラスターでのレートリミットもサポートされていません。 -
適用シーン
Windows開発環境;厳密なレートリミットを必要としないビジネス;CC攻撃からの防御。
apcu
-
拡張のインストール
apcu拡張をインストールする必要があり、php.iniに次の設定が必要です。apc.enabled=1 apc.enable_cli=1
php.iniの場所がわからない場合は、
php --ini
コマンドで確認できます。 -
紹介
performanceはmemoryよりわずかに低く、マルチプロセス間でレートリミットデータを共有します。 -
使用制限
クラスターはサポートされていません。 -
適用シーン
どの開発環境にも対応;オンライン単一ホストのレートリミットシーン;クラスターで厳密なレートリミットが必要ないシーン;CC攻撃からの防御。
redis
-
依存関係
redis拡張をインストールし、Redisコンポーネントをインストールする必要があります。インストールコマンドは次の通りです。composer require -W illuminate/redis illuminate/events
-
紹介
性能はapcuより低いですが、単独ホストとクラスターの両方で精度の高いレートリミットをサポートします。 -
適用シーン
開発環境;オンライン単一ホスト環境;クラスター環境