Etap 15: Zabezpieczenie panelu administracyjnego
Zabezpieczenie panelu administracyjnego¶
Panel administracyjny powinien być dostępny tylko dla zaufanych osób. Zabezpieczenie tego obszaru strony internetowej można wykonać przy użyciu komponentu Symfony Security.
Podobnie jak w przypadku Twig, komponent bezpieczeństwa jest już zainstalowany poprzez zależności przechodnie (ang. transitive dependencies). Dodajmy komponent wprost do pliku composer.json
projektu:
1 | $ symfony composer req security
|
Definiowanie encji (ang. entity) użytkownika¶
Nawet jeśli uczestnicy nie będą w stanie utworzyć własnych kont na stronie internetowej, stworzymy w pełni funkcjonalny system uwierzytelniania do administracji. W związku z tym będziemy mieli tylko jedno konto – administracyjne.
Pierwszym krokiem jest zdefiniowanie encji User
. Aby uniknąć nieporozumień, nazwijmy encję Admin
.
Aby zintegrować encję Admin
z systemem uwierzytelniania (ang. authentication system) Symfony Security, encja musi spełnić pewne wymagania. Na przykład potrzebuje atrybutu (ang. property) password
.
Użyj polecenia make:user
aby utworzyć encję Admin
zamiast tradycyjnego make:entity
:
1 | $ symfony console make:user Admin
|
Odpowiedz na pytania interaktywne: chcemy używać Doctrine do przechowywania kont administracyjnych (yes
), używać username
jako unikalnej nazwy użytkownika, a każdy użytkownik będzie miał hasło (yes
).
Wygenerowana klasa zawiera metody takie jak getRoles()
, eraseCredentials()
oraz kilka innych, które są potrzebne w systemie uwierzytelniania Symfony.
Jeśli chcesz dodać więcej atrybutów do encji użytkownika Admin
, użyj make:entity
.
Dodajmy metodę __toString()
, której używa 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
@@ -75,6 +75,11 @@ class Admin implements UserInterface
return $this;
}
+ public function __toString(): string
+ {
+ return $this->username;
+ }
+
/**
* @see UserInterface
*/
|
Oprócz wygenerowania encji Admin
, polecenie zaktualizowało również konfigurację zabezpieczeń, aby połączyć encję z systemem uwierzytelniania:
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:
+ encoders:
+ 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)/
|
Pozwalamy Symfony wybrać najlepszy możliwy algorytm kodowania haseł (który będzie ewoluował w czasie).
Czas wygenerować migrację i uaktualnić schemat bazy danych:
1 2 | $ symfony console make:migration
$ symfony console doctrine:migrations:migrate -n
|
Generowanie hasła dla konta administracyjnego¶
Nie stworzymy dedykowanego systemu do tworzenia kont administracyjnych. Będziemy mieli tylko jedno konto administracyjne. Loginem będzie admin
i musimy zakodować hasło.
Wymyśl dowolne hasło i uruchom poniższą komendę, aby wygenerować hasło w postaci zakodowanej:
1 | $ symfony console security:encode-password
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | Symfony Password Encoder Utility
================================
Type in your password to be encoded:
>
------------------ ---------------------------------------------------------------------------------------------------
Key Value
------------------ ---------------------------------------------------------------------------------------------------
Encoder used Symfony\Component\Security\Core\Encoder\MigratingPasswordEncoder
Encoded password $argon2id$v=19$m=65536,t=4,p=1$BQG+jovPcunctc30xG5PxQ$TiGbx451NKdo+g9vLtfkMy4KjASKSOcnNxjij4gTX1s
------------------ ---------------------------------------------------------------------------------------------------
! [NOTE] Self-salting encoder used: the encoder generated its own built-in salt.
[OK] Password encoding succeeded
|
Tworzenie konta administracyjnego¶
Dodaj konto administracyjne poprzez zapytanie 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')"
|
Zwróć uwagę na filtrowanie (ang. escaping) znaku $
w wartości kolumny hasła; odfiltruj je wszystkie!
Konfigurowanie systemu uwierzytelniania¶
Teraz, gdy mamy konto administracyjne, możemy zabezpieczyć panel administracyjny. Symfony obsługuje kilka strategii uwierzytelniania. Wykorzystajmy klasyczny i popularny system uwierzytelniania formularzem.
Uruchom polecenie make:auth
aby zaktualizować konfigurację zabezpieczeń, wygenerować szablon (ang. template) logowania i utworzyć klasę uwierzytelniania (ang. authenticator):
1 | $ symfony console make:auth
|
Wybierz 1
aby wygenerować klasę uwierzytelniania dla formularza logowania (ang. form authenticator), nazwij klasę AppAuthenticator
, kontroler SecurityController
i wygeneruj URL /logout
(yes
).
Polecenie zaktualizowało konfigurację zabezpieczeń w celu połączenia (ang. wire) wygenerowanych klas:
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
|
Jak wynika z wskazówki na wyjściu komendy, musimy dostosować trasę (ang. route) w metodzie onAuthenticationSuccess()
, aby przekierować użytkownika, gdy pomyślnie się zaloguje:
1 2 3 4 5 6 7 8 9 10 11 12 | --- a/src/Security/AppAuthenticator.php
+++ b/src/Security/AppAuthenticator.php
@@ -96,8 +96,7 @@ class AppAuthenticator extends AbstractFormLoginAuthenticator implements Passwor
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('easyadmin'));
}
protected function getLoginUrl()
|
Wskazówka
Skąd mam wiedzieć, że trasa EasyAdmin to easyadmin
? Nie wiem. Ale uruchomiłem poniższą komendę, która pokazuje związek między nazwami tras (ang. route) a ścieżkami:
1 | $ symfony console debug:router
|
Dodawanie reguł kontroli dostępu do autoryzacji¶
System bezpieczeństwa składa się z dwóch części: uwierzytelniania (ang. authentication) i autoryzacji (ang. authorization). Tworząc konto administracyjne, nadaliśmy mu rolę ROLE_ADMIN
. Ograniczmy ścieżkę /admin
do użytkowników mających tę rolę poprzez dodanie reguły do access_control
:
1 2 3 4 5 6 7 8 9 | --- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -34,5 +34,5 @@ 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 }
|
Reguły w access_control
ograniczają dostęp za pomocą wyrażeń regularnych (ang. regular expressions). Przy próbie uzyskania dostępu do adresu URL, który zaczyna się od /admin
, system bezpieczeństwa sprawdzi czy zalogowany użytkownik posiada rolę ROLE_ADMIN
.
Uwierzytelnianie za pomocą formularza logowania¶
Próba dostępu do panelu administracyjnego skutkuje przekierowaniem na stronę logowania i prośbą o podanie loginu i hasła:

Zaloguj się używając nazwy użytkownika admin
i hasła, które zostało zakodowane wcześniej. Jeśli użyto dokładnie mojego polecenia SQL, hasło brzmi admin
.
Zauważ, że EasyAdmin automatycznie rozpoznaje system uwierzytelniania Symfony:

Spróbuj kliknąć w link „Wyloguj się”. Udało się! Mamy pełni zabezpieczony panel administracyjny.
Informacja
Jeśli chcesz stworzyć w pełni funkcjonalny system uwierzytelniania formularzem, spójrz na polecenie make:registration-form
.
- « Previous Etap 14: Przyjmowanie informacji zwrotnych za pomocą formularzy
- Next » Etap 16: Ochrona przed spamem przy pomocy API
This work, including the code samples, is licensed under a Creative Commons BY-NC-SA 4.0 license.