Защита административной панели
Административная панель должна быть доступна только доверенным лицам. Защитить её можно с помощью компонента 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
.
Двигаемся дальше