bvtterfly/sliding-window-rate-limiter

此包已废弃且不再维护。未建议替代包。

laravel的滑动窗口速率限制器

0.1.0 2022-04-14 07:21 UTC

README

🚨 本包已废弃 🚨

我不再使用Laravel,无法证明维护此包所需的时间。因此,我选择废弃它。您可以使用我的代码进行分支并维护自己的副本。

Laravel滑动窗口速率限制器

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

此包提供了一种简单的方法来在指定的时间窗口内限制任何操作。您可能熟悉Laravel的速率限制器,它有类似的API,但它使用滑动窗口算法并需要Redis。

安装

您可以通过composer安装此包

composer require bvtterfly/sliding-window-rate-limiter

您可以使用以下命令发布配置文件

php artisan vendor:publish --tag="sliding-window-rate-limiter-config"

这是发布配置文件的内容

return [
    'use' => 'default',
];

该包依赖于Redis,并需要Redis连接,您可以选择使用哪个Redis连接。

用法

可以使用Bvtterfly\SlidingWindowRateLimiter\Facades\SlidingWindowRateLimiter外观与速率限制器交互。

速率限制器提供的最简单方法是attempt方法,该方法为给定秒数限制一个动作。该方法返回一个结果对象,指定尝试是否成功以及剩余尝试次数。如果尝试失败,您可以得到再次进行操作所需的时间。

use Bvtterfly\SlidingWindowRateLimiter\Facades\SlidingWindowRateLimiter;

$result = SlidingWindowRateLimiter::attempt(
    'send-message:'.$user->id,
    $maxAttempts = 5,
    $decayInSeconds = 60
);

if ($result->successful()) {
    // attempt is successful, do awesome thing... 
} else {
    // attempt is failed, you can get when you can retry again
    // use $result->retryAfter for getting the number of seconds until the action is available again
    // or use $result->availableAt() for getting UNIX timestamp instead.

}

您可以在SlidingWindowRateLimiter上调用以下方法

tooManyAttempts

/**
 * Determine if the given key has been "accessed" too many times.
 *
 * @param  string  $key
 * @param  int  $maxAttempts
 * @param  int  $decay
 * 
 * @return bool
 */
public function tooManyAttempts(string $key, int $maxAttempts, int $decay = 60): bool

attempts

/**
 * Get the number of attempts for the given key for decay time in seconds.
 *
 * @param  string  $key
 * @param  int  $decay
 * 
 * @return int
 */
public function attempts(string $key, int $decay = 60): int

resetAttempts

/**
 * Reset the number of attempts for the given key.
 *
 * @param  string  $key
 * 
 * @return mixed
 */
public function resetAttempts(string $key): mixed

remaining

/**
 * Get the number of retries left for the given key.
 *
 * @param  string  $key
 * @param  int  $maxAttempts
 * @param  int  $decay
 *
 * @return int
 */
public function remaining(string $key, int $maxAttempts, int $decay = 60): int

clear

/**
 * Clear the number of attempts for the given key.
 *
 * @param  string  $key
 *
 * @return void
 */
public function clear(string $key)

availableIn

/**
 * Get the number of seconds until the "key" is accessible again.
 *
 * @param  string  $key
 * @param  int  $maxAttempts
 * @param  int  $decay
 *
 * @return int
 */
public function availableIn(string $key, int $maxAttempts, int $decay = 60): int

retriesLeft

/**
* Get the number of retries left for the given key.
*
* @param  string  $key
* @param  int  $maxAttempts
* @param  int  $decay
*
* @return int
*/
public function retriesLeft(string $key, int $maxAttempts, int $decay = 60): int

路由速率限制

此包包含一个用于路由速率限制的throttle中间件。它可以替换默认的Laravel throttle中间件以使用此包的速率限制器。唯一的区别是它尝试从SlidingWindowRateLimiter获取命名的速率限制器,或者作为后备,它将从Laravel速率限制器中获取它们。

您可能希望更改应用程序HTTP内核(App\Http\Kernel)中的throttle中间件的映射,以使用\Bvtterfly\SlidingWindowRateLimiter\Http\Middleware\ThrottleRequests类。

为了使路由速率限制工作,必须为速率限制器进行配置。Laravel速率限制器包含一个基于分钟的系统工作的速率限制类(Illuminate\Cache\RateLimiting\Limit)。但此包旨在允许基于秒的系统进行速率限制操作,因此它包含自己的速率限制器类并允许您为少于1分钟配置速率限制器。尽管如此,为了方便使用此包,它仍然支持默认的Laravel速率限制器。

定义速率限制器

SlidingWindowRateLimiter速率限制器在很大程度上基于Laravel的速率限制器。它仅在基于秒这一点上有所不同。因此,在开始之前,请确保阅读有关Laravel文档的介绍Laravel文档

限制配置是Bvtterfly\SlidingWindowRateLimiter\RateLimiting\Limit类的实例,并包含一些有用的“构建器”方法,可以快速定义您的速率限制。速率限制器名称可以是您希望的任何字符串。

对于在45秒内限制500个请求

use Bvtterfly\SlidingWindowRateLimiter\RateLimiting\Limit;
use Bvtterfly\SlidingWindowRateLimiter\Facades\SlidingWindowRateLimiter;
 
/**
 * Configure the rate limiters for the application.
 *
 * @return void
 */
protected function configureRateLimiting()
{
    SlidingWindowRateLimiter::for('global', function (Request $request) {
        return Limit::perSeconds(45, 500);
    });
}

如果传入的请求超出指定的速率限制,Laravel将自动返回一个带有429 HTTP状态码的响应。如果您希望定义速率限制器返回的响应,可以使用response方法

SlidingWindowRateLimiter::for('global', function (Request $request) {
    return Limit::perSeconds(45, 500)->response(function () {
        return response('Custom response...', 429);
    });
});

您可以拥有多个速率限制。此配置将限制每30秒100个请求和每天1000个请求

SlidingWindowRateLimiter::for('global', function (Request $request) {
    return [
        Limit::perSeconds(30, 100),
        Limit::perDay(1000)
    ];
});

传入的HTTP请求实例将传递给速率限制回调函数,速率限制可能会根据用户或请求动态计算

SlidingWindowRateLimiter::for('uploads', function (Request $request) {
    return $request->user()->vipCustomer()
                ? Limit::none()
                : Limit::perMinute(100);
});

有时您可能希望根据某个任意值来分割速率限制。例如,您可能希望允许每个经过身份验证的用户ID每分钟访问指定路由100次请求,以及每个IP地址的访客每分钟10次请求。使用by方法,您可以创建如下速率限制

SlidingWindowRateLimiter::for('uploads', function (Request $request) {
    return $request->user()
                ? Limit::perMinute(100)->by($request->user()->id)
                : Limit::perMinute(10)->by($request->ip());
});

将速率限制器附加到路由

可以使用throttle中间件将速率限制器附加到路由或路由组。该throttle中间件接受要分配给路由的速率限制器的名称

Route::middleware(['throttle:media'])->group(function () {
    
    Route::post('/audio', function () {
        //
    })->middleware('throttle:uploads');
 
    Route::post('/video', function () {
        //
    })->middleware('throttle:uploads');
    
});

测试

composer test

变更日志

有关最近更改的更多信息,请参阅变更日志

安全漏洞

有关如何报告安全漏洞,请参阅我们的安全策略

致谢

许可证

MIT许可证(MIT)。有关更多信息,请参阅许可证文件