Laravel Spark - 我可以限制计划每月 API 次调用和每个 minute/hour 次 API 次调用吗?

Laravel Spark - Can I limit plan API calls per month and API calls per minute/hour?

我想使用 Laravel Spark 为 API 创建不同的许可证。我想限制每个月 API 次调用以及每个 hour/minute 次调用。例如,基本许可证将允许每月 10 000 次 api 调用,但我还想限制同一帐户每个 hour/minute 的 API 调用。这可以用 laravel spark 来完成吗?

有:节流和 rate_limit,但我可以限制每个月和每个 hour/minute 的 API 调用总数吗?例如:每月总共 10 000 次 api 调用,每个 hour/minute?

最多调用 60 api 次

根据文档,我可以根据 minute/hour 限制访问:https://laravel.com/docs/6.x/routing#rate-limiting

像这样的东西结合了节流和速率限制:

Route::middleware('auth:api', 'throttle:10|rate_limit,1')->group(function () {     
Route::get('/user', function () { // }); 
});

但我的主要问题是如何将每个 minute/hour 的速率限制与每月限制相结合?

来自同一文档页面:

You may also combine this functionality with dynamic rate limits. For example, if your User model contains a rate_limit attribute, you may pass the name of the attribute to the throttle middleware so that it is used to calculate the maximum request count for authenticated users

因此,鉴于上述情况,您可以在您的 User 模型上添加一个 accessor,以根据他们当前的订阅计划获取速率限制值:

class User extends Authenticatable
{
    public function getRateLimitAttribute()
    {
        // Get license if it's a model

        if ($license === 'basic') {
            return 10000;
        }

        // Return some default here
    }
}

然后您可以像这样使用动态速率限制值:

Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
    // Rate-limited routes
});

至于每月限额,您需要在某处保留一个计数器,并在每次请求时进行检查。您可以在另一个中间件中记录每个 API 请求:

class LogRequest
{
    public function handle($request, Closure $next)
    {
        return $next($request);
    }

    public function terminate($request, $response)
    {
        LogRequestJob::dispatch($request);
    }
}
class LogRequestJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public function __construct(Request $request)
    {
        $this->request = $request;
    }

    public function handle()
    {
        // Insert row for user to log request
        RequestLog::create([
            'user_id' => $this->request->user()->getKey(),
            'path' => $this->request->path(),
            // Store any other request data you're interested in
        ]);
    }
}

然后您需要在处理请求之前再次使用中间件检查计数:

use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;

class CheckRequestInLimit
{
    public function handle($request, Closure $next)
    {
        $year = Carbon::now()->year;
        $month = Carbon::now()->month;
        $count = RequestLog::user($request->user())->year($year)->month($month)->count();
        $limit = $request->user()->monthly_limit; // another accessor

        if ($count < $limit) {
            return $next($request);
        }

        // Count is equal to (or greater than) limit; throw exception
        $retryAfter = Carbon::today()->addMonth()->startOfMonth();
        $message = 'You have exceeded your monthly limit';

        throw new TooManyRequestsHttpException($retryAfter, $message);
    }
}

希望这能给你带来思考!

2021 年 11 月 1 日编辑: 此答案是针对 Laravel 的旧版本编写的。 Laravel 后来介绍了 rate limiting 可以为上述问题提供更简洁的解决方案:

RateLimiter::for('api', function (Request $request) {
    return [
        Limit::perHour(60)->by($request->user()->getKey()),
        Limit::perDay(10000, 30)->by($request->user()->getKey()),
    ];
});