Mettere in sicurezza il pannello amministrativo
L'interfaccia del pannello amministrativo dovrebbe essere accessibile solo da persone autorizzate. La sicurezza di quest'area del sito può essere garantita usando il componente Security di Symfony.
Definire un'entity "User"
Anche se i partecipanti non saranno in grado di creare i propri account sul sito, creeremo un sistema di autenticazione completamente funzionante per l'amministratore del sito e avremo, quindi, un solo utente.
Il primo passo è quello di definire un'entity User
. Per evitare confusione, chiamiamola Admin
.
Per integrarsi con il sistema di autenticazione, l'entity Admin
deve seguire alcuni requisiti specifici. Per esempio, ha bisogno di una proprietà password
.
Utilizzare il comando dedicato make:user
per creare l'entity Admin
al posto del tradizionale make:entity
:
1
$ symfony console make:user Admin
Rispondere alle domande interattive: "we want to use Doctrine to store the admins" (yes
), "use username
for the unique display name of admins", e "each user will have a password" (yes
).
La classe generata contiene metodi come getRoles()
, eraseCredentials()
e alcuni altri metodi che sono necessari al sistema di autenticazione di Symfony.
Se si desidera aggiungere altre proprietà all'utente Admin
, utilizzare il comando make:entity
.
Aggiungiamo un metodo __toString()
affinché EasyAdmin lo possa utilizzare per la visualizzazione:
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
*/
Oltre a generare l'entity Admin
, il comando ha anche aggiornato la configurazione di sicurezza per collegare l'entity con il sistema di autenticazione:
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)/
Lasciamo a Symfony la scelta del miglior algoritmo possibile per l'hash delle password (che si evolverà nel tempo).
È giunto il momento di generare gli script di migrazione e migrare il database:
1 2
$ symfony console make:migration
$ symfony console doctrine:migrations:migrate -n
Generare una password per l'utente amministratore
Non svilupperemo un sistema dedicato per la creazione di account amministrativi. Come detto precedentemente, avremo sempre un solo amministratore. Il nome utente sarà admin
e dobbiamo generare l'hash della password.
Selezionare App\Entity\Admin
e scegliere la password desiderata, poi lanciare il seguente comando per generare l'hash della password:
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
Creare un amministratore
Inserire l'utente amministratore tramite un'istruzione 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')"
Si noti l'escape del simbolo $
nel valore della colonna della password;
Configurare l'autenticazione
Ora che abbiamo un utente amministratore, possiamo proteggere il pannello amministrativo. Symfony supporta diverse strategie di autenticazione. Usiamo il classico e popolare sistema di autenticazione con form.
Eseguire il comando make:auth
per aggiornare la configurazione, generare un template per il login e creare un authenticator:
1
$ symfony console make:auth
Selezionare 1
per generare un'autenticazione con form, chiamare la classe authenticator AppAuthenticator
, il controller SecurityController
, e generare un URL /logout
(yes
).
Il comando ha aggiornato la configurazione di sicurezza per collegare le classi generate:
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
Come suggerito dall'output del comando, abbiamo bisogno di personalizzare la rotta nel metodo onAuthenticationSuccess()
per reindirizzare l'utente quando accede:
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
Come faccio a ricordare che il percorso per EasyAdmin è admin
(in base alla configurazione in App\Controller\Admin\DashboardController
)? Non occorre ricordarselo. Possiamo dare un'occhiata al file, ma possiamo anche eseguire il seguente comando, che mostra l'associazione tra i nomi delle rotte e i percorsi:
1
$ symfony console debug:router
Aggiungere regole di accesso e autorizzazione
Un sistema di sicurezza è composto da due parti: autenticazione e autorizzazione. Quando abbiamo creato l'utente amministratore, gli abbiamo assegnato il ruolo ROLE_ADMIN
. Limitiamo la sezione /admin
solo agli utenti che hanno questo ruolo aggiungendo una regola a 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:
Le regole in access_control
limitano l'accesso usando delle espressioni regolari. Quando si tenta di accedere a un URL che inizia con /admin
, il sistema di sicurezza verificherà se l'utente connesso abbia il ruolo ROLE_ADMIN
.
Autenticazione tramite form di login
Se si tenta di accedere al pannello amministrativo, si dovrebbe ora essere reindirizzati alla pagina di login, dove sono richiesti nome utente e password:
Effettuare il login utilizzando admin
e come password quella in chiaro che è stata precedentemente scelta. Se avete copiato esattamente il precedente comando SQL, la password è admin
.
Notare che EasyAdmin riconosce automaticamente il sistema di autenticazione di Symfony:
Provare a cliccare sul link "Sign out". Ecco fatto! Un pannello amministrativo completamente al sicuro.
Note
Se si vuole creare un sistema completo di autenticazione con form, dare uno sguardo al comando make:registration-form
.