Защита административной панели
Административная панель должна быть доступна только доверенным лицам. Защитить её можно с помощью компонента Symfony Security.
Определение сущности пользователя
Несмотря на то, что посетители не смогут создавать учётные записи на сайте самостоятельно, мы создадим полнофункциональную систему аутентификации для администратора. Поэтому у нас будет только один пользователь — администратор сайта.
На первом шаге давайте определим сущность User. Чтобы избежать возможной путаницы, назовём её Admin.
Для интеграции сущности Admin с системой аутентификации Symfony Security, она должна соответствовать определённым требованиям. Например, наличие свойства password является обязательным.
Для создания сущности Admin выполните специальную команду make:user вместо обычной make:entity.
1
$ symfony console make:user Admin
Ответьте на вопросы в терминале: использовать ли Doctrine для хранения администраторов (yes), какое из свойств использовать для отображения имени администратора (username), должен ли каждый пользователь иметь пароль (yes).
Созданный класс содержит методы вроде getRoles(), eraseCredentials() и многие другие, необходимые Symfony для системы аутентификации.
Используйте команду make:entity, если вам нужно добавить дополнительные свойства в сущность Admin.
Также давайте добавим метод __toString(), так как его использует EasyAdmin:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
--- a/src/Entity/Admin.php
+++ b/src/Entity/Admin.php
@@ -54,6 +54,11 @@ class Admin implements UserInterface, PasswordAuthenticatedUserInterface
return (string) $this->username;
}
+ public function __toString(): string
+ {
+ return $this->username;
+ }
+
/**
* @see UserInterface
*/
Помимо создания самой сущности Admin, команда также обновит конфигурацию безопасности и свяжет сущность с системой аутентификации:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -1,7 +1,15 @@
security:
+ password_hashers:
+ App\Entity\Admin:
+ algorithm: auto
+
# https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers
providers:
- in_memory: { memory: null }
+ # used to reload user from session & other features (e.g. switch_user)
+ app_user_provider:
+ entity:
+ class: App\Entity\Admin
+ property: username
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
Выбор наилучшего алгоритма для хеширования паролей (который со временем будет меняться) мы оставим на усмотрение Symfony.
Пришло время создать миграцию и применить её к базе данных:
1 2
$ symfony console make:migration
$ symfony console doctrine:migrations:migrate -n
Создание пароля для администратора
Так как у нас будет всего лишь один администратор, мы не будем разрабатывать отдельную систему для создания администраторских учётных записей. В качестве логина используем admin и захешируем пароль.
Придумайте любой пароль и при помощи следующей команды захешируйте его:
1
$ symfony console security:hash-password
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Symfony Password Hash Utility
=============================
Type in your password to be hashed:
>
------------------ ---------------------------------------------------------------------------------------------------
Key Value
------------------ ---------------------------------------------------------------------------------------------------
Hasher used Symfony\Component\PasswordHasher\Hasher\MigratingPasswordHasher
Password hash $argon2id$v=19$m=65536,t=4,p=1$BQG+jovPcunctc30xG5PxQ$TiGbx451NKdo+g9vLtfkMy4KjASKSOcnNxjij4gTX1s
------------------ ---------------------------------------------------------------------------------------------------
! [NOTE] Self-salting hasher used: the hasher generated its own built-in salt.
[OK] Password hashing succeeded
Создание администратора
Добавьте администратора, используя следующий SQL-запрос:
1 2 3
$ symfony run psql -c "INSERT INTO admin (id, username, roles, password) \
VALUES (nextval('admin_id_seq'), 'admin', '[\"ROLE_ADMIN\"]', \
'\$argon2id\$v=19\$m=65536,t=4,p=1\$BQG+jovPcunctc30xG5PxQ\$TiGbx451NKdo+g9vLtfkMy4KjASKSOcnNxjij4gTX1s')"
Обратите внимание на экранирование знака $ в столбце пароля; экранируйте их все!
Настройка аутентификации
Теперь, когда у нас есть пользователь с правами администратора, мы можем защитить административную панель. Symfony поддерживает несколько стратегий аутентификации. Давайте воспользуемся классической и достаточно популярной системой аутентификации с помощью формы.
Выполните команду make:auth, чтобы обновить конфигурацию безопасности, сгенерировать шаблон с формой входа, а также создать аутентификатор (класс для управления аутентификацией):
1
$ symfony console make:auth
Выберите 1 для создания аутентификатора с формой входа, назовите класс аутентификатора — AppAuthenticator, контроллер — SecurityController и ответьте yes, чтобы добавить маршрут для выхода из системы по пути /logout.
Для связывания вновь созданных классов, команда обновит настройки безопасности:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -16,6 +16,13 @@ security:
security: false
main:
anonymous: lazy
+ guard:
+ authenticators:
+ - App\Security\AppAuthenticator
+ logout:
+ path: app_logout
+ # where to redirect after logout
+ # target: app_any_route
# activate different ways to authenticate
# https://symfony.com/doc/current/security.html#firewalls-authentication
Благодаря подсказке во время выполнения команды, для перенаправления пользователя в случае успешного входа, нам также необходимо изменить маршрут в методе onAuthenticationSuccess():
1 2 3 4 5 6 7 8 9 10 11 12 13
--- a/src/Security/AppAuthenticator.php
+++ b/src/Security/AppAuthenticator.php
@@ -49,9 +49,7 @@ class AppAuthenticator extends AbstractLoginFormAuthenticator
return new RedirectResponse($targetPath);
}
- // For example:
- //return new RedirectResponse($this->urlGenerator->generate('some_route'));
- throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
+ return new RedirectResponse($this->urlGenerator->generate('admin'));
}
protected function getLoginUrl(Request $request): string
Tip
Откуда я знаю, что маршрутом к EasyAdmin является admin (который задан в App\Controller\Admin\DashboardController)? Нет, я не написал его по памяти. Его можно узнать из файла класса, но лучше выполнить следующую команду, которая отобразит все имеющиеся маршруты вместе с их путями:
1
$ symfony console debug:router
Добавление правил контроля доступа для авторизации
Система безопасности состоит из двух частей: аутентификация и авторизация . При создании администратора мы добавили ему роль ROLE_ADMIN. Чтобы ограничить доступ к разделу /admin только для пользователей имеющих эту роль, необходимо добавить правило в access_control:
1 2 3 4 5 6 7 8 9 10 11
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -35,7 +35,7 @@ security:
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used
access_control:
- # - { path: ^/admin, roles: ROLE_ADMIN }
+ - { path: ^/admin, roles: ROLE_ADMIN }
# - { path: ^/profile, roles: ROLE_USER }
when@test:
Правила access_control ограничивают доступ с помощью регулярных выражений. При переходе по URL-адресу, который начинается с /admin, система безопасности проверит наличие роли ROLE_ADMIN у авторизованного пользователя.
Аутентификация через форму входа
Теперь при открытии административной панели вы автоматически окажетесь на странице входа, где вам будет предложено ввести логин и пароль:
Войдите в систему, используя логин admin и незашифрованный пароль, который был захеширован вами ранее. Если вы корректно скопировали мою SQL-команду, то пароль будет admin.
Обратите внимание, что EasyAdmin автоматически распознает систему аутентификации Symfony:
Попробуйте нажать на ссылку "Sign out". Всё готово! Теперь у вас есть полностью защищённая административная панель.
Note
Если вы хотите создать полноценную систему аутентификации с использованием формы, используйте команду make:registration-form.