50% discount in conference replays
2020 and 2021 events
In English, French, German, Polish and Spanish

Защита административной панели

Защита административной панели

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

Аутентификация через форму входа

Теперь при открытии административной панели вы автоматически окажетесь на странице входа, где вам будет предложено ввести логин и пароль:

/login/

Войдите в систему, используя логин admin и незашифрованный пароль, который был захеширован вами ранее. Если вы корректно скопировали мою SQL-команду, то пароль будет admin.

Обратите внимание, что EasyAdmin автоматически распознает систему аутентификации Symfony:

/admin/

Попробуйте нажать на ссылку "Sign out". Всё готово! Теперь у вас есть полностью защищённая административная панель.

Note

Если вы хотите создать полноценную систему аутентификации с использованием формы, используйте команду make:registration-form.

This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.