Das Admin-Backend absichern

Das Admin-Backend absichern

Die Admin-Backend-Schnittstelle sollte nur für vertrauenswürdige Personen zugänglich sein. Die Sicherung dieses Bereichs der Website kann mit der Symfony Security-Komponente erfolgen.

Eine User Entity definieren

Auch wenn die Teilnehmerinnen nicht in der Lage sein werden, ihre eigenen Konten auf der Website zu erstellen, werden wir ein voll funktionsfähiges Authentifizierungssystem für einen Administratorin einrichten. Wir werden daher nur einen einzigen Benutzerin haben.

Der erste Schritt ist die Definition einer User-Entity. Um Verwechslungen zu vermeiden, benennen wir sie stattdessen Admin.

Um die Admin-Entity im Authentifizierungssystem von Symfony Security zu integrieren, muss sie einige spezifische Anforderungen erfüllen. Zum Beispiel benötigt sie ein password-Feld.

Verwende den make:user-Befehl anstatt dem üblichen make::entity-Befehl, um die Admin-Entity zu erstellen:

1
$ symfony console make:user Admin

Beantworte die interaktiven Fragen: Wir wollen Doctrine verwenden, um die Admins zu speichern (yes), verwende username für den eindeutigen Anzeigenamen von Admins, und jeder Benutzerin wird ein Passwort haben (yes).

Die generierte Klasse enthält Methoden wie getRoles(), eraseCredentials(), und ein paar andere, die vom Symfony-Authentifizierungssystem benötigt werden.

Falls Du demr Admin-Benutzerin weitere Eigenschaften hinzufügen möchtest, verwende make:entity.

Lass uns noch eine __toString()-Methode hinzufügen, weil EasyAdmin diese gerne benutzt:

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
      */

Zusätzlich zum Erzeugen der Admin-Entity aktualisierte der Befehl auch die Sicherheitskonfiguration, um die Entity mit dem Authentifizierungssystem zu verbinden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -5,14 +5,18 @@ security:
         Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
     # https://symfony.com/doc/current/security.html#loading-the-user-the-user-provider
     providers:
-        users_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)/
             security: false
         main:
             lazy: true
-            provider: users_in_memory
+            provider: app_user_provider

             # activate different ways to authenticate
             # https://symfony.com/doc/current/security.html#the-firewall

Wir lassen Symfony den besten verfügbaren Algorithmus zum Hashen von Passwörtern auswählen (diese werden sich im Laufe der Zeit weiterentwickeln).

Zeit, eine Migration zu generieren und die Datenbank zu migrieren:

1
2
$ symfony console make:migration
$ symfony console doctrine:migrations:migrate -n

Ein Passwort für dieen Admin-Benutzerin generieren

Wir werden kein spezielles System zur Erstellung von Admin-Konten entwickeln. Auch hier werden wir immer nur einen Admin haben. Das Login wird admin sein und wir müssen den Passwort-Hash generieren.

Wähle App\Entity\Admin mit einem beliebigen Passwort und führe den folgenden Befehl aus, um den Passwort-Hash zu generieren:

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

Einen Administratorin erstellen

Füge dieen Admin-Benutzerin über einen SQL-Befehl hinzu:

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')"

Siehst Du, wie das $-Zeichen in unserem Wert in der Passwortspalte escaped wurde? Escapen nie vergessen!

Die Sicherheits-Authentifizierung konfigurieren

Jetzt, da wir einen Admin-Benutzerin haben, können wir das Admin-Backend absichern. Symfony unterstützt mehrere Authentifizierungsstrategien. Lass uns ein klassisches und verbreitetes Formular-Authentifizierungssystem verwenden.

Führe den make:auth-Befehl aus, um die Sicherheitskonfiguration zu aktualisieren, ein Login-Template zu generieren und einen Authentifikator zu erstellen.

1
$ symfony console make:auth

Wähle 1, um einen Login-Formular-Authentifikator zu generieren, benenne die Authentifikatorklasse AppAuthenticator, den Controller SecurityController und generiere eine /logout-URL (yes).

Der Befehl hat die Sicherheitskonfiguration aktualisiert, um die generierten Klassen zu verbinden:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -17,6 +17,11 @@ security:
         main:
             lazy: true
             provider: app_user_provider
+            custom_authenticator: 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#the-firewall

Wie von der Befehlsausgabe angedeutet, müssen wir die Route in der onAuthenticationSuccess()-Methode anpassen, um Benutzer*innen nach erfolgreicher Anmeldung umzuleiten:

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

Wie merke ich mir, dass die EasyAdmin-Route (wie in App\Controller\Admin\DashboardController konfiguriert) admin ist? Gar nicht. Du kannst in die Datei schauen, oder aber auch den folgenden Befehl ausführen, der die Zuordnung zwischen Routennamen und Pfaden anzeigt:

1
$ symfony console debug:router

Berechtigungsregeln für die Zugriffskontrolle hinzufügen

Ein Sicherheitssystem besteht aus zwei Teilen: Authentifizierung und Autorisierung. Beim Erstellen desr Admin-Benutzersin haben wir ihmr die ROLE_ADMIN-Rolle gegeben. Wir schränken den /admin-Bereich auf Benutzerinnen mit dieser Rolle ein, indem wir eine Regel zu access_control hinzufügen:

1
2
3
4
5
6
7
8
9
10
11
--- a/config/packages/security.yaml
+++ b/config/packages/security.yaml
@@ -32,7 +32,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:

Die access_control-Regeln schränken den Zugriff durch reguläre Ausdrücke ein. Beim Versuch, auf eine URL zuzugreifen, die mit /admin beginnt, überprüft das Sicherheitssystem, dass die angemeldeten Benutzer*innen die ROLE_ADMIN-Rolle besitzen.

Über das Login-Formular authentifizieren

Wenn Du versuchst, auf das Admin-Backend zuzugreifen, solltest Du nun auf die Login-Seite weitergeleitet und aufgefordert werden, einen Usernamen und ein Passwort einzugeben:

/login/

Melde Dich mit admin und dem Klartext-Passwort an, das Du zuvor als Hash gewählt hast. Wenn Du meinen SQL-Befehl genau kopiert hast, lautet das Passwort admin.

Beachte, dass EasyAdmin das Symfony-Authentifizierungssystem automatisch erkennt:

/admin/

Versuche, auf den Link "Abmelden" zu klicken. Und fertig! Ein vollständig gesicherter Backend-Adminbereich.

Note

Wenn Du ein vollwertiges Formular-Authentifizierungssystem erstellen möchtest, wirf einen Blick auf den make:registration-form-Befehl.

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