Comment authentifier les utilisateurs avec le composant de sécurité Symfony

Dans cet article, vous allez apprendre à configurer l'authentification d'utilisateur en PHP à l'aide du composant Symfony Security. En plus de l'authentification, je vais vous montrer comment utiliser son autorisation basée sur les rôles, que vous pouvez étendre selon vos besoins..

Le composant de sécurité Symfony

Le composant de sécurité Symfony vous permet de configurer des fonctionnalités de sécurité telles que l’authentification, l’autorisation basée sur les rôles, les jetons CSRF, etc., très facilement. En fait, il est divisé en quatre sous-composants que vous pouvez choisir en fonction de vos besoins..

Le composant Sécurité comprend les sous-composants suivants:

  • symfony / security-core
  • symfony / security-http
  • symfony / security-csrf
  • symfony / security-acl

Dans cet article, nous allons explorer la fonctionnalité d’authentification fournie par le symfony / security-core composant.

Comme d'habitude, nous commencerons par les instructions d'installation et de configuration, puis nous explorerons quelques exemples concrets pour illustrer les concepts clés..

Installation et configuration

Dans cette section, nous allons installer le composant Symfony Security. Je suppose que vous avez déjà installé Composer sur votre système. Nous en aurons besoin pour installer le composant de sécurité disponible sur Packagist..

Alors allez-y et installez le composant de sécurité en utilisant la commande suivante.

$ composer a besoin de symfony / security

Nous allons charger les utilisateurs de la base de données MySQL dans notre exemple, nous aurons donc également besoin d'une couche d'abstraction de base de données. Installons l'une des couches d'abstraction de base de données les plus populaires: Doctrine DBAL.

$ compositeur nécessite doctrine / dbal

Cela aurait dû créer le composer.json fichier, qui devrait ressembler à ceci:

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

Modifions le composer.json fichier à ressembler au suivant.

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

Comme nous avons ajouté un nouveau classmap entrée, mettons à jour l'autoloader du compositeur en exécutant la commande suivante.

$ compositeur dump -o

Maintenant, vous pouvez utiliser le Sfauth espace de noms pour charger automatiquement les classes sous la src annuaire.

C'est donc la partie installation, mais comment êtes-vous censé l'utiliser? En fait, il s’agit simplement d’inclure le autoload.php fichier créé par Composer dans votre application, comme indiqué dans l'extrait suivant.

Un exemple du monde réel

Commençons par le flux d’authentification habituel fourni par le composant Symfony Security..

  • La première chose à faire est de récupérer les informations d'identification de l'utilisateur et de créer un jeton non authentifié..
  • Ensuite, nous allons passer un jeton non authentifié au gestionnaire d'authentification pour validation..
  • Le gestionnaire d'authentification peut contenir différents fournisseurs d'authentification, et l'un d'entre eux sera utilisé pour authentifier la demande de l'utilisateur actuel. La logique d'authentification de l'utilisateur est définie dans le fournisseur d'authentification..
  • Le fournisseur d'authentification contacte le fournisseur d'utilisateur pour récupérer l'utilisateur. Il incombe au fournisseur d’utilisateurs de charger les utilisateurs à partir du back-end correspondant..
  • Le fournisseur d'utilisateurs tente de charger l'utilisateur à l'aide des informations d'identification fournies par le fournisseur d'authentification. Dans la plupart des cas, le fournisseur d’utilisateur renvoie l’objet utilisateur qui implémente la Interface utilisateur interface.
  • Si l'utilisateur est trouvé, le fournisseur d'authentification renvoie un jeton non authentifié et vous pouvez le stocker pour les demandes suivantes..

Dans notre exemple, nous allons faire correspondre les informations d'identification de l'utilisateur avec la base de données MySQL. Nous devrons donc créer le fournisseur d'utilisateurs de la base de données. Nous allons également créer le fournisseur d'authentification de base de données qui gère la logique d'authentification. Et enfin, nous allons créer la classe User, qui implémente le Interface utilisateur interface.

La classe d'utilisateurs

Dans cette section, nous allons créer la classe User qui représente l'entité utilisateur dans le processus d'authentification..

Allez-y et créez le src / User / User.php fichier avec le contenu suivant.

nom d'utilisateur = $ nom d'utilisateur; $ this-> mot de passe = $ mot de passe; $ this-> rôles = $ rôles;  fonction publique getUsername () return $ this-> nom d'utilisateur;  fonction publique getPassword () return $ this-> mot de passe;  fonction publique getRoles () return explode (",", $ this-> rôles);  fonction publique getSalt () return "; fonction publique eraseCredentials () 

L’important est que la classe User doit implémenter la sécurité Symfony. Interface utilisateur interface. En dehors de cela, il n'y a rien d'extraordinaire ici.

La classe de fournisseur de base de données

Il incombe au fournisseur d’utilisateurs de charger les utilisateurs à partir du back-end. Dans cette section, nous allons créer le fournisseur d’utilisateurs de base de données, qui charge l’utilisateur à partir de la base de données MySQL..

Créons le src / User / DatabaseUserProvider.php fichier avec le contenu suivant.

connexion = $ connexion;  fonction publique loadUserByUsername ($ username) return $ this-> getUser ($ username);  fonction privée getUser ($ nom_utilisateur) $ sql = "SELECT * FROM sf_users WHERE nom_utilisateur =: nom"; $ stmt = $ this-> connection-> prepare ($ sql); $ stmt-> bindValue ("name", $ username); $ stmt-> execute (); $ row = $ stmt-> fetch (); if (! $ row ['nomutilisateur'])) $ exception = new UsernameNotFoundException (sprintf ('Nomutilisateur "% s" introuvable dans la base de données.', $ row ['nomutilisateur'])); $ exception-> setUsername ($ username); jeter $ exception;  else retour nouvel utilisateur ($ row ['nomutilisateur'], $ row ['mot de passe'], $ row ['rôles']));  public function refreshUser (UserInterface $ user) if (! $ $ instance d'utilisateur de User) lève une nouvelle exception UnsupportedUserException (sprintf ('Les instances de "% s" ne sont pas prises en charge.', get_class ($ user));  return $ this-> getUser ($ user-> getUsername ());  fonction publique supportsClass ($ class) return 'Sfauth \ User \ User' === $ class; 

Le fournisseur de l’utilisateur doit implémenter le UserProviderInterface interface. Nous utilisons la doctrine DBAL pour effectuer les opérations liées à la base de données. Comme nous avons mis en place le UserProviderInterface interface, nous devons mettre en œuvre le loadUserByUsername, rafraîchirUtilisateur, et supportClass les méthodes.

le loadUserByUsername méthode devrait charger l'utilisateur par le nom d'utilisateur, et cela se fait dans le getUser méthode. Si l'utilisateur est trouvé, nous retournons le correspondant Sfauth \ Utilisateur \ Utilisateur objet, qui implémente le Interface utilisateur interface.

D'autre part, le rafraîchirUtilisateur met à jour la méthode fournie Utilisateur objet en récupérant les dernières informations de la base de données.

Et finalement, le supportClass méthode vérifie si le DatabaseUserProvider fournisseur prend en charge la classe d'utilisateurs fournie.

La classe de fournisseur d'authentification de base de données

Enfin, nous devons implémenter le fournisseur d'authentification d'utilisateur, qui définit la logique d'authentification, à savoir comment un utilisateur est authentifié. Dans notre cas, nous devons faire correspondre les informations d'identification de l'utilisateur à la base de données MySQL. Nous devons donc définir la logique d'authentification en conséquence..

Allez-y et créez le src / User / DatabaseAuthenticationProvider.php fichier avec le contenu suivant.

userProvider = $ userProvider;  fonction protégée retrieveUser ($ username, usernamePasswordToken $ token) $ user = $ token-> getUser (); if ($ user instanceof UserInterface) return $ user;  try $ user = $ this-> userProvider-> loadUserByUsername ($ username); if (! $ user instanceof UserInterface) lance une nouvelle AuthenticationServiceException ('Le fournisseur de l'utilisateur doit renvoyer un objet UserInterface.');  return $ user;  catch (UsernameNotFoundException $ e) $ e-> setUsername ($ username); jeter $ e;  catch (\ Exception $ e) $ e = new AuthenticationServiceException ($ e-> getMessage (), 0, $ e); $ e-> setToken ($ token); jeter $ e;  Fonction protégée checkAuthentication (UserInterface $ user, UsernamePasswordToken $ token) $ currentUser = $ token-> getUser (); if ($ currentUser instanceof UserInterface) if ($ currentUser-> getPassword ()! == $ user-> getPassword ()) jette new AuthenticationException ('Les informations d'identification ont été modifiées à partir d'une autre session.');  else $ password = $ token-> getCredentials (); if (empty ($ password)) lance la nouvelle AuthenticationException ('Le mot de passe ne peut pas être vide.');  if ($ user-> getPassword ()! = md5 ($ password)) lance la nouvelle AuthenticationException ('Le mot de passe est invalide.'); 

le DatabaseAuthenticationProvider Le fournisseur d'authentification étend la UserAuthenticationProvider classe abstraite. Par conséquent, nous devons mettre en œuvre le récupérerUser et checkAuthentication méthodes abstraites.

Le métier de récupérerUser méthode consiste à charger l'utilisateur à partir du fournisseur d'utilisateur correspondant. Dans notre cas, il utilisera le DatabaseUserProvider fournisseur pour charger l'utilisateur depuis la base de données MySQL.

D'autre part, le checkAuthentication méthode effectue les vérifications nécessaires afin d’authentifier l’utilisateur actuel. Veuillez noter que j'ai utilisé la méthode MD5 pour le cryptage de mot de passe. Bien sûr, vous devez utiliser des méthodes de cryptage plus sécurisées pour stocker les mots de passe des utilisateurs..

Comment ça marche tout à fait

Jusqu'à présent, nous avons créé tous les éléments nécessaires à l'authentification. Dans cette section, nous verrons comment tout mettre en place pour configurer la fonctionnalité d’authentification..

Allez-y et créez le db_auth.php fichier et le remplir avec le contenu suivant.

 'mysql: // USERNAME: PASSWORD @ HOSTNAME / DATABASE_NAME'), new \ Doctrine \ DBAL \ Configuration ()); // initialiser notre fournisseur d'utilisateurs de base de données personnalisé $ userProvider = new DatabaseUserProvider ($ doctrineConnection); // nous utiliserons UserChecker par défaut, il est utilisé pour vérifier les vérifications supplémentaires comme le verrouillage de compte / expiré, etc. // vous pouvez implémenter les vôtres en implémentant l'interface UserCheckerInterface $ userChecker = new UserChecker (); // initie notre fournisseur d'authentification de base de données personnalisé $ dbProvider = new DatabaseAuthenticationProvider ($ userProvider, $ userChecker, 'frontend'); // init gestionnaire de fournisseur d'authentification $ authenticationManager = new AuthenticationProviderManager (array ($ dbProvider)); try // init un / pw, vous les récupérez généralement à partir de la variable $ _POST, soumise par l'utilisateur final $ username = 'admin'; $ password = 'admin'; // récupère le jeton non authentifié $ unauthenticatedToken = new UsernamePasswordToken ($ username, $ password, 'frontend'); // authentifie l'utilisateur et obtient le jeton authentifié $ authentifiéToken = $ authentificationManager-> authentifié ($ unauthenticatedToken); // nous avons le jeton authentifié (l'utilisateur est connecté maintenant), il peut être stocké dans une session pour une utilisation ultérieure echo $ authentifiéToken; echo "\ n";  catch (AuthenticationException $ e) echo $ e-> getMessage (); echo "\ n"; 

Rappelez-vous le flux d'authentification qui a été discuté au début de cet article - le code ci-dessus reflète cette séquence.

La première chose à faire était de récupérer les informations d'identification de l'utilisateur et de créer un jeton non authentifié..

$ unauthenticatedToken = new UsernamePasswordToken ($ username, $ password, 'frontend');

Ensuite, nous avons transmis ce jeton au gestionnaire d'authentification pour validation..

// authentifie l'utilisateur et obtient le jeton authentifié $ authentifiéToken = $ authentificationManager-> authentifié ($ unauthenticatedToken);

Lorsque la méthode authenticate est appelée, beaucoup de choses se passent dans les coulisses.

Tout d'abord, le gestionnaire d'authentification sélectionne un fournisseur d'authentification approprié. Dans notre cas, c'est le DatabaseAuthenticationProvider fournisseur d'authentification, qui sera sélectionné pour l'authentification.

Ensuite, il récupère l’utilisateur par le nom d’utilisateur du DatabaseUserProvider fournisseur d'utilisateur. Finalement, le checkAuthentication méthode effectue les vérifications nécessaires pour authentifier la demande de l'utilisateur actuel.

Si vous souhaitez tester le db_auth.php script, vous aurez besoin de créer le sf_users table dans votre base de données MySQL.

CREATE TABLE 'sf_users' ('id' int (11) NON NULL AUTO_INCREMENT, 'nom d'utilisateur' varchar (255) NON NULL, 'mot de passe' varchar (255) NON NULL, 'rôles' enum ('enregistré', 'modérateur', ' 'admin') DEFAULT NULL, PRIMARY KEY ('id')) ENGINE = InnoDB; INSERT INTO 'sf_users' VALUES (1, 'admin', '21232f297a57a5a743894a0e4a801fc3', 'admin');

Allez-y et lancez le db_auth.php script pour voir comment ça se passe. En cas de réussite, vous devriez recevoir un jeton authentifié, comme indiqué dans l'extrait de code suivant..

$ php db_auth.php UsernamePasswordToken (utilisateur = "admin", authentifié = true, roles = "admin")

Une fois l'utilisateur authentifié, vous pouvez stocker le jeton authentifié dans la session pour les demandes suivantes..

Et avec cela, nous avons terminé notre démonstration d'authentification simple!

Conclusion

Aujourd'hui, nous avons examiné le composant Symfony Security, qui vous permet d'intégrer des fonctionnalités de sécurité dans vos applications PHP. Plus précisément, nous avons discuté de la fonctionnalité d'authentification fournie par le sous-composant symfony / security-core, et je vous ai montré un exemple de la manière dont cette fonctionnalité peut être implémentée dans votre propre application..

N'hésitez pas à poster vos pensées en utilisant le flux ci-dessous!