Benutzerauthentifizierung mit der Symfony Security-Komponente

In diesem Artikel erfahren Sie, wie Sie die Benutzerauthentifizierung in PHP mit der Komponente Symfony Security einrichten. Neben der Authentifizierung zeige ich Ihnen, wie Sie die rollenbasierte Autorisierung verwenden, die Sie je nach Bedarf erweitern können.

Die Symfony-Sicherheitskomponente

Mit der Symfony Security-Komponente können Sie Sicherheitsfunktionen wie Authentifizierung, rollenbasierte Autorisierung, CSRF-Token und vieles mehr sehr einfach einrichten. Tatsächlich ist es in vier Unterkomponenten unterteilt, aus denen Sie je nach Bedarf auswählen können.

Die Sicherheitskomponente hat die folgenden Unterkomponenten:

  • Symfony / Sicherheitskern
  • Symfony / Sicherheit-http
  • symfony / security-csrf
  • symfony / security-acl

In diesem Artikel werden wir die Authentifizierungsfunktion, die von bereitgestellt wird, erkunden Symfony / Sicherheitskern Komponente.

Wie üblich beginnen wir mit den Installations- und Konfigurationsanweisungen. Anschließend untersuchen wir einige Beispiele aus der Praxis, um die wichtigsten Konzepte zu veranschaulichen.

Installation und Konfiguration

In diesem Abschnitt installieren wir die Symfony Security-Komponente. Ich gehe davon aus, dass Sie Composer bereits auf Ihrem System installiert haben. Wir benötigen ihn, um die bei Packagist verfügbare Sicherheitskomponente zu installieren.

Fahren Sie also fort und installieren Sie die Sicherheitskomponente mit dem folgenden Befehl.

$ composer erfordert Symfony / Sicherheit

In unserem Beispiel werden wir Benutzer aus der MySQL-Datenbank laden. Daher benötigen wir auch eine Datenbankabstraktionsschicht. Installieren wir eine der beliebtesten Datenbankabstraktionsschichten: Doctrine DBAL.

$ composer erfordert doctrine / dbal

Das hätte das schaffen sollen composer.json Datei, die so aussehen sollte:

"erfordern": "symfony / security": "^ 4.1", "doctrine / dbal": "^ 2.7"

Ändern wir das composer.json Datei wie die folgende aussehen.

"erfordern": "symfony / security": "^ 4.1", "doctrine / dbal": "^ 2.7", "autoload": "psr-4": "Sfauth \\": "src" , "classmap": ["src"]

Da haben wir ein neues hinzugefügt Classmap Wenn Sie einen Eintrag eingeben, aktualisieren Sie den Autoloader des Composers, indem Sie den folgenden Befehl ausführen.

$ composer dump -o

Jetzt können Sie die Sfauth Namespace zum automatischen Laden von Klassen unter src Verzeichnis.

Das ist also der Installationsteil, aber wie soll man es verwenden? In der Tat ist es nur eine Frage der Einbeziehung der autoload.php Datei, die von Composer in Ihrer Anwendung erstellt wurde, wie im folgenden Snippet gezeigt.

Ein reales Beispiel

Lassen Sie uns zunächst den üblichen Authentifizierungsfluss durchgehen, der von der Komponente Symfony Security bereitgestellt wird.

  • Als Erstes müssen Sie die Anmeldeinformationen des Benutzers abrufen und ein nicht authentifiziertes Token erstellen.
  • Als Nächstes übergeben wir ein nicht authentifiziertes Token zur Validierung an den Authentifizierungsmanager.
  • Der Authentifizierungsmanager kann verschiedene Authentifizierungsanbieter enthalten, von denen einer zur Authentifizierung der aktuellen Benutzeranforderung verwendet wird. Die Logik, wie der Benutzer authentifiziert wird, wird im Authentifizierungsanbieter definiert.
  • Der Authentifizierungsanbieter kontaktiert den Benutzeranbieter, um den Benutzer abzurufen. Es liegt in der Verantwortung des Benutzeranbieters, Benutzer vom jeweiligen Backend aus zu laden.
  • Der Benutzeranbieter versucht, den Benutzer mit den vom Authentifizierungsanbieter bereitgestellten Anmeldeinformationen zu laden. In den meisten Fällen gibt der Benutzeranbieter das Benutzerobjekt zurück, das das implementiert Benutzeroberfläche Schnittstelle.
  • Wenn der Benutzer gefunden wird, gibt der Authentifizierungsanbieter ein nicht authentifiziertes Token zurück, und Sie können dieses Token für die nachfolgenden Anforderungen speichern.

In unserem Beispiel werden die Benutzeranmeldeinformationen mit der MySQL-Datenbank abgeglichen. Daher müssen wir den Datenbankbenutzerprovider erstellen. Wir erstellen auch den Datenbankauthentifizierungsanbieter, der die Authentifizierungslogik verarbeitet. Und zum Schluss erstellen wir die User-Klasse, die das implementiert Benutzeroberfläche Schnittstelle.

Die Benutzerklasse

In diesem Abschnitt erstellen wir die Benutzerklasse, die die Benutzerentität im Authentifizierungsprozess darstellt.

Mach weiter und erstelle das src / User / User.php Datei mit folgendem Inhalt.

Benutzername = $ Benutzername; $ this-> password = $ password; $ this-> rollen = $ rollen;  public function getUsername () return $ this-> Benutzername;  public function getPassword () return $ this-> Kennwort;  public function getRoles () return explode (",", $ this-> rolls);  public function getSalt () return "; öffentliche Funktion eraseCredentials () 

Wichtig ist, dass die Benutzerklasse Symfony Security implementiert Benutzeroberfläche Schnittstelle. Abgesehen davon gibt es hier nichts Außergewöhnliches.

Die Datenbankanbieterklasse

Es liegt in der Verantwortung des Benutzeranbieters, Benutzer vom Backend aus zu laden. In diesem Abschnitt erstellen wir den Datenbankbenutzerprovider, der den Benutzer aus der MySQL-Datenbank lädt.

Lass uns die erstellen src / User / DatabaseUserProvider.php Datei mit folgendem Inhalt.

Verbindung = $ Verbindung;  public function loadUserByUsername ($ username) return $ this-> getUser ($ username);  private Funktion getUser ($ username) $ sql = "SELECT * FROM sf_users WHERE Benutzername =: name"; $ stmt = $ this-> verbindung-> vorbereiten ($ sql); $ stmt-> bindValue ("name", $ username); $ stmt-> execute (); $ row = $ stmt-> fetch (); if (! $ row ['username']) $ exception = new UsernameNotFoundException (sprintf ('Username "% s" wurde nicht in der Datenbank gefunden.', $ row ['username'])); $ exception-> setUsername ($ username); $ ausnahme werfen;  else return new user ($ row ['username'], $ row ['password'], $ row ['rollen']);  public function refreshUser (UserInterface $ user) if (! $ user instanceof User) neue unsupportedUserException auslösen (sprintf ('Instanzen von "% s" werden nicht unterstützt.', get_class ($ user)));  $ this-> getUser zurückgeben ($ user-> getUsername ());  public function supportClass ($ class) return 'Sfauth \ User \ User' === $ class; 

Der Benutzeranbieter muss das implementieren UserProviderInterface Schnittstelle. Wir verwenden die Doktrin DBAL, um die datenbankbezogenen Vorgänge auszuführen. Da haben wir die umgesetzt UserProviderInterface Schnittstelle müssen wir die implementieren loadUserByUsername, refreshUser, und unterstütztKlasse Methoden.

Das loadUserByUsername Die Methode sollte den Benutzer über den Benutzernamen laden, und das erfolgt in der getUser Methode. Wird der Benutzer gefunden, senden wir den entsprechenden zurück Sfauth \ Benutzer \ Benutzer Objekt, das das implementiert Benutzeroberfläche Schnittstelle.

Auf der anderen Seite die refreshUser Methode aktualisiert die gelieferte Nutzer Objekt durch Abrufen der neuesten Informationen aus der Datenbank.

Und zum Schluss die unterstütztKlasse Methode prüft, ob die DatabaseUserProvider Provider unterstützt die angegebene Benutzerklasse.

Die Klasse der Datenbankauthentifizierungsanbieter

Schließlich müssen wir den Benutzerauthentifizierungsanbieter implementieren, der die Authentifizierungslogik definiert, wie ein Benutzer authentifiziert wird. In unserem Fall müssen wir die Anmeldeinformationen der Benutzer mit der MySQL-Datenbank abgleichen. Daher müssen wir die Authentifizierungslogik entsprechend definieren.

Mach weiter und erstelle das src / Benutzer / DatabaseAuthenticationProvider.php Datei mit folgendem Inhalt.

userProvider = $ userProvider;  geschützte Funktion retrieveUser ($ username, UsernamePasswordToken $ token) $ user = $ token-> getUser (); if ($ user Instanz von UserInterface) return $ user;  try $ user = $ this-> userProvider-> loadUserByUsername ($ username); if (! $ Benutzerinstanz von UserInterface) Neue AuthenticationServiceException auslösen ('Der Benutzeranbieter muss ein UserInterface-Objekt zurückgeben.');  $ Benutzer zurückgeben;  catch (UsernameNotFoundException $ e) $ e-> setUsername ($ username); werfen Sie $ e;  catch (\ Exception $ e) $ e = neue AuthenticationServiceException ($ e-> getMessage (), 0, $ e); $ e-> setToken ($ token); werfen Sie $ e;  geschützte Funktion checkAuthentication (UserInterface $ user, UsernamePasswordToken $ token) $ currentUser = $ token-> getUser (); if ($ currentUser-Instanz von UserInterface) if ($ currentUser-> getPassword ()! == $ user-> getPassword ()) Neue AuthenticationException auslösen ('Anmeldeinformationen wurden von einer anderen Sitzung geändert.');  else $ password = $ token-> getCredentials (); if (empty ($ password)) Neue AuthenticationException auslösen ('Passwort darf nicht leer sein.');  if ($ user-> getPassword ()! = md5 ($ password)) Neue AuthenticationException auslösen ('Passwort ist ungültig.'); 

Das DatabaseAuthenticationProvider Authentifizierungsanbieter erweitert die UserAuthenticationProvider abstrakte Klasse. Daher müssen wir das implementieren retrieveUser und checkAuthentication abstrakte Methoden.

Der Job der retrieveUser Die Methode besteht darin, den Benutzer vom entsprechenden Benutzeranbieter zu laden. In unserem Fall wird es verwendet DatabaseUserProvider Benutzerprovider, um den Benutzer aus der MySQL-Datenbank zu laden.

Auf der anderen Seite die checkAuthentication Diese Methode führt die erforderlichen Prüfungen durch, um den aktuellen Benutzer zu authentifizieren. Bitte beachten Sie, dass ich die MD5-Methode zur Kennwortverschlüsselung verwendet habe. Natürlich sollten Sie sicherere Verschlüsselungsmethoden verwenden, um Benutzerkennwörter zu speichern.

Wie es zusammen funktioniert

Bisher haben wir alle notwendigen Elemente für die Authentifizierung erstellt. In diesem Abschnitt erfahren Sie, wie Sie die Authentifizierungsfunktion einrichten können.

Mach weiter und erstelle das db_auth.php Datei und füllen Sie es mit dem folgenden Inhalt.

 'mysql: // USERNAME: PASSWORD @ HOSTNAME / DATABASE_NAME'), neu \ Doctrine \ DBAL \ Configuration ()); // init unseren benutzerdefinierten Datenbankbenutzerprovider $ userProvider = new DatabaseUserProvider ($ doctrineConnection); // Wir verwenden den Standard-UserChecker. Er wird verwendet, um zusätzliche Überprüfungen wie Kontosperrung / Abgelaufenes usw. zu überprüfen. // Sie können Ihre eigenen implementieren, indem Sie die BenutzerCheckerInterface-Schnittstelle implementieren. // init unseren benutzerdefinierten DB-Authentifizierungsanbieter $ dbProvider = new DatabaseAuthenticationProvider ($ userProvider, $ userChecker, 'frontend'); // Init-Authentifizierungsanbieter-Manager $ authenticationManager = new AuthenticationProviderManager (Array ($ dbProvider)); try // init un / pw, normalerweise erhalten Sie diese über die $ _POST-Variable, die vom Endbenutzer angegeben wird. $ username = 'admin'; $ password = 'admin'; // nicht authentifiziertes Token erhalten $ unauthenticatedToken = new UsernamePasswordToken ($ Benutzername, $ Kennwort, 'Frontend'); // Benutzer authentifizieren und authentifiziertes Token erhalten $ authenticatedToken = $ authenticationManager-> authenticate ($ unauthenticatedToken); // wir haben das authentifizierte Token (Benutzer ist jetzt angemeldet), es kann zur späteren Verwendung in einer Sitzung gespeichert werden echo $ authenticatedToken; Echo "\ n";  catch (AuthenticationException $ e) echo $ e-> getMessage (); Echo "\ n"; 

Erinnern Sie sich an den Authentifizierungsablauf, der zu Beginn dieses Artikels erläutert wurde. Der obige Code spiegelt diese Reihenfolge wider.

Zunächst mussten die Benutzeranmeldeinformationen abgerufen und ein nicht authentifiziertes Token erstellt werden.

$ unauthenticatedToken = new UsernamePasswordToken ($ Benutzername, $ Kennwort, 'Frontend');

Als Nächstes haben wir dieses Token zur Validierung an den Authentifizierungsmanager übergeben.

// Benutzer authentifizieren und authentifiziertes Token erhalten $ authenticatedToken = $ authenticationManager-> authenticate ($ unauthenticatedToken);

Wenn die Authentifizierungsmethode aufgerufen wird, geschieht hinter den Kulissen viel.

Zunächst wählt der Authentifizierungsmanager einen geeigneten Authentifizierungsanbieter aus. In unserem Fall ist es das DatabaseAuthenticationProvider Authentifizierungsanbieter, der für die Authentifizierung ausgewählt wird.

Als Nächstes wird der Benutzer anhand des Benutzernamens aus dem Server abgerufen DatabaseUserProvider Benutzeranbieter. Endlich, das checkAuthentication Diese Methode führt die erforderlichen Prüfungen zur Authentifizierung der aktuellen Benutzeranforderung durch.

Möchten Sie das testen? db_auth.php Skript, müssen Sie das erstellen sf_users Tabelle in Ihrer MySQL-Datenbank.

CREATE TABLE 'sf_users' ('id' int (11) NOT NULL AUTO_INCREMENT, 'Benutzername' varchar (255) NOT NULL, 'Passwort' varchar (255) NOT NULL, 'Rollen' enum ('registriert', 'Moderator', 'admin') DEFAULT NULL, PRIMARY KEY ('id')) ENGINE = InnoDB; INSERT INTO 'sf_users' VALUES (1, 'admin', '21232f297a57a5a743894a0e4a801fc3', 'admin');

Mach weiter und lauf die db_auth.php Skript, um zu sehen, wie es geht. Nach erfolgreichem Abschluss sollten Sie ein authentifiziertes Token erhalten, wie im folgenden Snippet gezeigt.

$ php db_auth.php UsernamePasswordToken (user = "admin", authenticated = true, Rollen = "admin")

Sobald der Benutzer authentifiziert ist, können Sie das authentifizierte Token in der Sitzung für die nachfolgenden Anforderungen speichern.

Und damit haben wir unsere einfache Authentifizierungs-Demo abgeschlossen!

Fazit

Heute haben wir uns die Komponente Symfony Security angesehen, mit der Sie Sicherheitsfunktionen in Ihre PHP-Anwendungen integrieren können. Insbesondere haben wir die Authentifizierungsfunktion der Unterkomponente symfony / security-core besprochen, und ich habe Ihnen ein Beispiel gezeigt, wie diese Funktionalität in Ihrer eigenen App implementiert werden kann.

Fühlen Sie sich frei, Ihre Gedanken mit dem untenstehenden Feed zu posten!