Auth for API in 5 minutes via Symfony 6

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.
Photo by FLY:D on Unsplash
Photo by FLY:D on Unsplash

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

Для этого разработчик создает новый репозиторий и там реализовует свое “чудо”. Это может быть как автономный инструмент который считает процент прибавок к зарплате за сверхурочные в зависимости от ставки и выслуги лет, так и более сложная стистема с доступом корпоративной базе данных.

В любом случае было бы не ответсвенно оставлять любой сервис предназначенный только для внутреннего испольхования, доступным публично. Ведь мы никогда наперед не знаем как и скакой целью мы можем стать цельбю для потенциального агента “Смитта”.


Самыми простыми способами защиты являются:

  • развернуть приложение внутри приватной сети, доступной лишь из под VPN.

  • Basic Auth.

  • Authentication token.

  • Normal auth with registration & login.

  • Corporate SSO (like google auth).

У каждого из этих способов есть свои плюсы и минусы в зависимости от токо в какой ситуации вы находитесь в текщий момент.

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

  • Мы хотим чтоб доступ был сотрудникам которые не под VPN.

  • У нас нет SSO(а если и был бы, то лень прикручивать ее к мелкому сервису написанному на коленке).

  • Делать полноценную регистрацию нет смысла так как нет ресурсов на модерацию.


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

Перейдем наконец к кодированию.

В нашем случае будет использован PHP 8.1 & symfony 6 & doctrine & security.

Также для удобства также будет использован бандл maker.

0. Для создания рабочей среды удобно использовать Docker. Вы можете воспользоваться заготовкой для создания полноценного локального окружения — Link.

  1. Устанавливаем фреймворк.

Полноценная инструкция на сайте самого Symfony https://symfony.com/doc/current/setup.html

  1. Устанавливаем зависимости: security, doctrine, maker(dev).

composer require doctrine

composer require symfony/security-bundle

composer require symfony/maker-bundle — dev

  1. Создаем модель пользователя.

./bin/console make:user
The name of the security user class (e.g. User) [User]:
 > User
Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]:
 > yes
Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]:
 > username
Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server).
Does this app need to hash/check user passwords? (yes/no) [yes]:
 > no
 created: src/Entity/User.php
 created: src/Repository/UserRepository.php
 updated: config/packages/security.yaml
Success!

4. Создадим и выполним миграцию для того чтоб в Базе данных появилась таблица ползователя:

./bin/console make:migration./bin/console doctrine:migrations:migrate

Теперь в нашей базе данных должны появится следующие 2 таблицы:

5. Делаем необходимые правки в конфигурации для возможности авторизоваться с помощью токена. Вы можете выбрать любое поле из вашей таблицы пользователя, не обязательно указывать именно — token.

// config/packages/security.yaml
security:
    password_hashers:
        Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
        App\Entity\User:
            algorithm: auto
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: token
    firewalls:
        dev:
            pattern: ^/(_(profiler|wdt)|css|images|js)/
            security: false
        main:
            lazy: true
            stateless: true
            provider: app_user_provider
            entry_point: App\Security\AuthenticationEntryPoint
            access_denied_handler: App\Security\AccessDeniedHandler
            custom_authenticators:
                - App\Security\ApiKeyAuthenticator
    access_control:
        - { path: ^/public, roles: PUBLIC_ACCESS }
        - { path: ^/, roles: IS_AUTHENTICATED_FULLY }

6. Теперь создадим необходимые классы в директории Security:

Ключ авторизации будет считываться с заголовков запроса, но если вам нужно иная реализация(например, из GET парметров) вы легко можете это изменить в методе authenticate . Название заголовка в котором ожидается токен аторизации хранится в константе — HEADER_AUTH_TOKEN .

Далее мы создадин класс который отвечает за генерацию ответа в случае если авторизация не пройдена.

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

7. Далее нам предстоит проверить работу нашей конфигурации. Для этого создадим контроллер с несколькими методами.

8. Перед тем как переходить к тестированию, нужно создать пользователя. Поскольку эта статья только об авторизации, то автор позволит себе создать пользователя простым sql запросом:

INSERT INTO demo.user (id, username, roles, token) VALUES (1, 'tester', '["ROLE_USER"]', 'super-secure-token');

9. Готово! Протестируем работу сервиса(я предпочитаю — Postman):


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

PS: В данной статье токен хранится в БД в не зашифрованном виде, но такой подход не рекомендуется использовать, т.к. данные пользователей могут оказаться под угрозой, более подробно можно почитать — тут.

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

Ссылка на репозиторий — Link.

Источник: https://habr.com/ru/post/669590/


Интересные статьи

Интересные статьи

Хочу поделиться опытом автоматизации экспорта заказов из Aliexpress в несколько CRM. Приведенные примеры написаны на PHP, но библиотеки для работы с Aliexpress есть и для...
В этой статье мы расскажем, как оптимизировать крупный проект в «Битрикс24» и увеличить его производительность в 3 раза, изменяя настройки MySQL и режим питания CPU. Дано Корпоративн...
VUE.JS - это javascript фрэймворк, с версии 18.5 его добавили в ядро битрикса, поэтому можно его использовать из коробки.
Однажды, в понедельник, мне пришла в голову мысль — "а покопаюсь ка я в новом ядре" (новым относительно, но об этом позже). Мысль не появилась на ровном месте, а предпосылками для нее стали: ...
Если честно, к Д7 у меня несколько неоднозначное отношение. В некоторых местах я попискиваю от восторга, а в некоторых хочется топать ногами и ругаться неприличными словами.