Аутентификация в Symfony 7: что нужно знать до начала
Прежде чем настраивать вход в приложение на Symfony, разберитесь с тремя понятиями: аутентификатор, провайдер пользователей и firewall. Иначе первая же ошибка в security.yaml остановит вас на полчаса.

К концу этого материала вы поймёте, из каких частей собирается вход пользователя в Symfony 7.x, что нужно установить и настроить до первой строки кода, и почему форма логина, которую вы напишете, не заработает без корректного security.yaml. Настройка базового входа с формой занимает около часа, если понимать, что вы делаете, и полдня — если тыкать наугад.
Речь идёт о новой системе безопасности Symfony (authenticator-based), которая стала единственной начиная с Symfony 6.0. Старую систему (Guard) в свежих проектах не встретить, но в статьях и ответах пятилетней давности она попадается — не путайте их, конфигурация несовместима.
Что нужно иметь до начала
Проверьте это заранее, чтобы не упереться в отсутствие пакета на середине настройки:
- PHP 8.2 или новее — минимальное требование Symfony 7.0;
- Composer и установленный проект на Symfony 7.x (полный или с добавленными пакетами);
- компонент безопасности:
composer require symfony/security-bundle; - если пользователи хранятся в базе — установленный Doctrine ORM (
composer require symfony/orm-pack) и настроенное подключение к БД в.env; - MakerBundle для генерации кода:
composer require --dev symfony/maker-bundle. Не обязателен, но экономит время на первом входе.
Если symfony/security-bundle не установлен, файла config/packages/security.yaml у вас просто не будет, и половина примеров из документации окажется бессмысленной.
Три понятия, без которых дальше нельзя
Система безопасности Symfony держится на трёх сущностях. Пока вы их не различаете, конфигурация выглядит как набор магических ключей.
User Provider — откуда берутся пользователи
Провайдер отвечает на вопрос «где искать пользователя по идентификатору». Самый частый вариант — entity: пользователи лежат в таблице БД и описаны Doctrine-сущностью. Есть и другие: memory (жёстко прописанные в конфиге, годятся для прототипа) и собственный провайдер под нестандартное хранилище.
Authenticator — как проверяется вход
Аутентификатор описывает механизм: форма с логином и паролем, HTTP Basic, JSON-запрос от SPA, API-токен в заголовке. Один firewall может использовать несколько аутентификаторов одновременно. Именно здесь чаще всего пишут собственный класс, если стандартные варианты не подходят.
Firewall — где всё это применяется
Firewall — это область приложения, к которой привязаны провайдер и аутентификаторы. Типичная ошибка новичка: настроить вход, но забыть, что запрос попал под firewall dev (для профайлера и ассетов), а не под ваш основной. Порядок firewall в конфиге важен — Symfony берёт первый подходящий по pattern, а не самый точный.
Большинство «у меня не работает логин» на самом деле — «мой запрос попал не под тот firewall». Прежде чем править аутентификатор, откройте профайлер и посмотрите, какой firewall сработал.
Как хранить пароли
Пароли в базе хранятся только в виде хеша. Symfony делает это через компонент PasswordHasher. По умолчанию в свежих проектах алгоритм задан как auto — Symfony сам выбирает надёжный алгоритм (на текущих версиях это bcrypt или Argon2, в зависимости от доступности в PHP) и умеет прозрачно перехешировать старые пароли при входе.
Ваша сущность пользователя должна реализовывать интерфейс PasswordAuthenticatedUserInterface, иначе хешер не поймёт, куда писать хеш. Сама сущность обычно реализует и UserInterface. Оба находятся в пространстве имён Symfony\Component\Security\Core\User.
Сгенерировать корректную сущность проще всего командой MakerBundle — она сама добавит нужные интерфейсы и поля:
# Symfony 7.x, MakerBundle установлен
php bin/console make:user
Команда спросит имя класса, поле-идентификатор (например, email), и нужно ли хранить пароль. После неё в проекте появится сущность и, при выборе entity-провайдера, автоматически пропишется провайдер в security.yaml. Проверка: откройте сгенерированный класс — у него должны быть методы getUserIdentifier() и getRoles().
Как выглядит минимальный security.yaml
Точную структуру ключей уточняйте в документации своей версии — Symfony периодически меняет рекомендуемые значения. Но общая логика такая:
- секция
password_hashers— какой алгоритм применять к какому классу; - секция
providers— где искать пользователей; - секция
firewallsс обязательнымdev(отключает безопасность для профайлера) и вашимmain; - секция
access_control— какие URL под какой ролью.
Не переписывайте security.yaml вручную с нуля по памяти. Дайте make:auth сгенерировать заготовку под форму входа и правьте её — так вы не промахнётесь мимо актуальных имён ключей.
Форма входа против API-токена: что выбрать сразу
До начала стоит решить, кто и как входит. Переделывать аутентификатор потом дороже, чем выбрать правильный на старте.
| Сценарий | Механизм | Чем платите |
|---|---|---|
| Классический сайт с HTML-страницами | form_login + сессия | состояние на сервере, нужна работа с сессиями |
| SPA на одном домене с бэкендом | json_login + сессия или кука | настройка CORS и CSRF при межсайтовых запросах |
| Публичное API для сторонних клиентов | кастомный AccessTokenAuthenticator | больше своего кода, нужно хранить и отзывать токены |
| Быстрый прототип без БД | memory-провайдер + HTTP Basic | не для продакшена, пользователи в конфиге |
Смешивать сессионный вход и токены в одном firewall можно, но это отдельная тема — здесь важно, что для API вам почти наверняка понадобится stateless: true в firewall, иначе Symfony попытается открыть сессию на каждый запрос.
Если не получилось
Пять ошибок, на которые уходит больше всего времени у новичка:
- «Unable to find the controller for path /login» — вы описали firewall с
form_login, но не создали контроллер и маршрут для страницы входа. Запуститеmake:authили добавьте маршрут вручную. - «The current user is not a User instance» или вход всегда неуспешен — провайдер не находит пользователя по идентификатору. Проверьте, что поле в
make:userи поле, которое отправляет форма, совпадают. - Вход проходит, но на защищённой странице снова редирект на логин — сессия не сохраняется. Частая причина: firewall помечен
stateless: true, но вы ждёте сессионного поведения. - Пароль не подходит, хотя вы уверены, что верный — при создании пользователя пароль записали в открытом виде вместо хеша. Хешируйте через
UserPasswordHasherInterface, а не пишите строку в поле напрямую. - «Cannot autowire service ... UserProviderInterface» — в конфиге несколько провайдеров и Symfony не знает, какой внедрить. Укажите провайдер явно в нужном firewall.
Что делать дальше
После того как базовый вход заработал, займитесь по порядку: настройте access_control и роли, чтобы разграничить доступ к разделам; включите ограничение попыток входа (login throttling) от перебора паролей; для сайта с формой проверьте, что CSRF-защита формы входа включена. Для API следующий шаг — механизм выдачи и отзыва токенов и stateless: true. Актуальные имена ключей конфигурации и доступные аутентификаторы всегда сверяйте с разделом Security официальной документации Symfony для вашей минорной версии — они меняются между релизами.
Карточки для маркетплейсов: Таблица товаров и папка фотографий на входе — комплект слайдов и описаний на выходе, по требованиям Wildberries и Ozon.
Спросить за 5 ₽Источники: Symfony Documentation — Security, Symfony Documentation — Passwords Hashing
Частые вопросы
У меня Symfony 6, а не 7 — примеры подойдут?
Обязательно ли использовать Doctrine и базу данных?
Логин не работает, хотя пароль верный. С чего начать?
Можно ли писать пароль в поле сущности напрямую?
Что делать, если после успешного входа меня снова выкидывает на страницу логина?
Guard и новый Authenticator — это одно и то же?
Материал носит информационный характер и подготовлен редакцией «Агентуры». Он не является офертой, рекламой или индивидуальной консультацией. Упомянутые продукты, компании и торговые знаки принадлежат их правообладателям. Перед принятием решений, влекущих юридические или финансовые последствия, обратитесь к профильному специалисту.