Skip to content

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

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

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

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

/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.
TOC
    Version