Хотите ограничить количество запросов в вашем api?

В этой статье я покажу реализацию промежуточного программного обеспечения, которое контролирует количество запросов на маршруте или группе маршрутов.

Я поясняю, что эта статья имеет образовательные цели, и она не должна быть единственным способом контроля доступа к api.


Представление сценария

Контроль количества запросов, которые получает ваше приложение, является интересной стратегией, поскольку позволяет избежать излишеств со стороны клиентских приложений.

Представляя себе сценарий, в котором наше приложение имеет обновленную информацию об эмиссии официальных документов, оно будет получать запросы от многих приложений одновременно с целью обновления собственных систем.

Это очень распространенный сценарий.

Бывает, что, учитывая большой объем информации, которую необходимо обработать, нашему приложению потребуется некоторое время, чтобы ответить на каждый запрос.

Среди приложений, обращающихся к нашей службе, есть одно, которое делает запросы каждые 5 секунд.

Если произвести быстрый подсчет, то только это приложение будет делать 12 запросов в минуту, 720 в час и 17 тысяч в день.

Чтобы избежать избытка и не навредить другим приложениям, мы введем блок для приложений, которые делают более 5 запросов в минуту.


Необходимые инструменты

  • PHP 8 или выше
  • Composer версии 2.0 или выше
  • Текстовый редактор

Существуют программы установки, в которые встроены PHP, MySQL и Apache (веб-сервер), такие как WAMPSERVER, XAMPP и Laragon. Я оставляю на ваше усмотрение выбор одного из этих пакетов или другого, который вам знаком.

В качестве текстового редактора я использую Visual Studio Code. Кроме того, что он бесплатный, он позволяет устанавливать несколько расширений.


Проект

Проект, который необходимо разработать, представляет собой приложение Laravel, известное как фреймворк для веб-разработки, и на момент написания этой статьи находится в версии 9.

Войдя в терминал по своему выбору, введите следующую команду:

composer create-project --prefer-dist laravel/laravel ratelimit
Войдите в полноэкранный режим Выход из полноэкранного режима

Время, необходимое для выполнения этого шага, может варьироваться в зависимости от скорости подключения к Интернету и конфигурации компьютера.

После завершения этого шага нам нужно получить доступ к директории проекта.


Middleware

Внутри каталога проекта мы создадим промежуточное ПО с помощью следующей команды:

php artisan make:middleware CustomRateLimit
Войдите в полноэкранный режим Выход из полноэкранного режима

По умолчанию в приложениях Laravel промежуточное ПО, созданное с помощью этой команды, будет сохранено в AppHttpMiddleware.

Используя текстовый редактор по вашему выбору, напишем метод handle() следующим образом:

<?php

namespace AppHttpMiddleware;

use Closure;
use IlluminateHttpRequest;
use IlluminateSupportFacadesRateLimiter;

class CustomRateLimit
{
    /**
     * Handle an incoming request.
     *
     * @param  IlluminateHttpRequest  $request
     * @param  Closure(IlluminateHttpRequest): (IlluminateHttpResponse|IlluminateHttpRedirectResponse)  $next
     * @return IlluminateHttpResponse|IlluminateHttpRedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        $executed = RateLimiter::attempt(
            'education'.$request->ip(),
            $perMinute = 5,
            function() {
            }
        );

        if (!$executed) {
            return response(
                [
                    'message' => 'Too many attempts.. try again in '.RateLimiter::availableIn('education').' seconds'
                ], 429);
        }
        return $next($request);
    }
}

Войдите в полноэкранный режим Выход из полноэкранного режима

Поясняя код, мы создаем ограничитель запросов через конструктор attempt, который имеет 3 обязательных параметра и 1 необязательный параметр.

Первый параметр получает имя ограничителя.

Это имя должно быть уникальным, и чтобы удовлетворить эту потребность, мы объединим текст ‘education’ с ip, полученным через переменную $request.

ПРИМЕЧАНИЕ: класс IlluminateHttpRequest инкапсулирует всю информацию http-запроса в течение его жизненного цикла.

Во втором параметре конструктора attempt мы сообщаем лимит запросов в минуту.

Третий параметр получает функцию обратного вызова. Реализация этой функции не является обязательной для валидации запросов. В этом случае мы сообщаем только заголовок метода, без реализации.

Последний параметр является необязательным. В нем мы изменяем интервал, в секундах, для проверки входящих запросов.

Например, если мы хотим блокировать на 5 минут, значение, которое нужно ввести в этот параметр, будет равно 300, или 60 секунд умножить на 5 минут.


Контроллер

Далее создадим контроллер.

php artisan make:controller RateLimitController
Войдите в полноэкранный режим Выход из полноэкранного режима

По умолчанию контроллеры, созданные с помощью вышеуказанной команды, сохраняются в AppHttpControllers.

Редактируя контроллер, мы реализуем метод для сброса счетчика запросов, разблокируя доступ к клиентскому приложению и возвращая пользовательское сообщение.

<?php

namespace AppHttpControllers;

use IlluminateHttpRequest;
use IlluminateSupportFacadesRateLimiter;

class RateLimitController extends Controller
{
    public function clearLimit(Request $request)
    {
        RateLimiter::clear('education'.$request->ip());

        return response(['message' => 'Attempts cleared for '.$request->ip()], 200);
    }
}

Войдите в полноэкранный режим Выход из полноэкранного режима

Поясняя код, мы делаем вызов метода clear(), который принимает в качестве параметра имя ограничителя.

Обратите внимание, что имя совпадает с именем, которое дано в реализации метода middleware handle(Request $request, Closure $next).


Маршрут

Теперь откроем файл маршрута, добавив два новых маршрута.

<?php

use IlluminateHttpRequest;
use IlluminateSupportFacadesRoute;
use AppHttpMiddlewareCustomRateLimit;
use AppHttpControllersRateLimitController;

Route::middleware([CustomRateLimit::class])->get('/rate-limit', function() {
    $date = new DateTime();
    $date->setTimezone(new DateTimeZone('-0300'));
    return $date->format('Y-m-d H:i:s');
});

Route::post('/rate-limit/clear', [RateLimitController::class, 'clearLimit']);

Войдите в полноэкранный режим Выход из полноэкранного режима

Первый путь — это увеличение количества запросов, чтобы достичь предела, который мы установили в промежуточном ПО.

Как только лимит будет достигнут, мы выведем пользовательское сообщение, информирующее о том, сколько времени (в секундах) осталось у клиентского приложения для выполнения новых запросов.

Второй маршрут направлен на обнуление счетчика путем вызова метода clearLimit() контроллера RateLimitController.


Тестирование

Снова заходим в терминал по вашему выбору, в папке проекта запускаем сервер на порту 8108.

Совет: внутри VSCode при использовании комбинации клавиш Ctrl+’ в нижней части IDE откроется терминал, уже в папке проекта.

php artisan serve --port=8108
Войдите в полноэкранный режим Выход из полноэкранного режима

Используя расширение Thunder для VSCode, мы будем выполнять запросы по первому маршруту, пока не будет достигнут лимит повторных попыток.

А затем мы сделаем запрос к маршруту, который сбросит счетчик повторных попыток.


Примечания

По умолчанию в приложениях Laravel кэш предварительно настроен на файл.

Однако можно изменить конфигурацию для использования с базами данных, Memcached или Redis, изменив переключатель 'default' в параметре
Класс ConfigCache.php.


Заключение

Целью этой статьи было показать, как реализовать способ избежать перегрузки при доступе к вашему приложению, временно блокируя некоторые приложения без остановки службы или нанесения вреда другим приложениям.

Я подчеркиваю, что этот подход не следует рассматривать как единственный вариант безопасности для вашего приложения.

Спасибо, что читаете, и до скорой встречи.


Используемые расширения

В веб-разработке хороший инструмент для тестирования api-запросов имеет большое значение.
Поэтому я оставляю здесь ссылку на расширение для VSCode Thunder RESTClient.

Расширение является бесплатным и очень надежным.


Для приложений Laravel расширение Laravel Extra Intellisense очень помогает в автоматическом включении ссылок.


Общественное хранилище

Проект опубликован на github в этом репозитории.

Оцените статью
devanswers.ru
Добавить комментарий