Maintenant que nous avons des utilisateurs dans notre CMS, nous devons leur donner la possibilité de se connecter en utilisant le plugin cakephp/authentication.Nous commencerons par nous assurer que les mots de passe sont stockés en toute sécurité dans notre base de données. Ensuite, nous allons fournir une connexion et une déconnexion en état de marche, et permettre aux nouveaux utilisateurs de s’inscrire.
Utilisez composer pour installer le Plugin d’authentification:
composer require cakephp/authentication:^2.0
Vous devez avoir créé le Controller
, Table
, Entity
et
les templates pour la table utilisateurs
de votre base de données. Vous pouvez
le faire manuellement comme vous l’avez fait auparavant pour ArticlesController, ou
vous pouvez utiliser le Shell bake pour générer les classes pour vous en tapant:
bin/cake bake all users
Si vous créez ou mettez à jour un utilisateur, vous remarquerez que les mots de passe sont stockés en clair, ce qui est évidemment très mauvais en terme de sécurité, règlons cela.
Corriger ce point nous permet de parler un peu plus de la couche model de CakePHP.
Dans CakePHP, nous séparons les méthodes qui s’occupent des collections d’objets
et d’un seul objet en différentes classes. Les méthodes qui s’occupent de
collections d’entity sont dans les classes Table
tandis que les fonctionnalités
liées à un seul enregistrement sont mises dans les classes Entity
.
Par exemple, hasher un mot de passe se fait enregistrement par enregistrement, c’est pourquoi nous allons implémenter ce comportement dans l’objet Entity. Puisque nous voulons hasher le mot de passe à chaque fois qu’il est défini, nous allons utiliser une méthode mutator/setter. Par convention, CakePHP appellera les méthodes de setter chaque fois qu’une propriété se voit affecter une valeur dans une entity. Ajoutons un setter pour le mot de passe. Dans src/Model/Entity/User.php, ajoutez le code suivant:
<?php
namespace App\Model\Entity;
use Authentication\PasswordHasher\DefaultPasswordHasher; // Ajouter cette ligne
use Cake\ORM\Entity;
class User extends Entity
{
// Tout le code de bake sera ici.
// Ajoutez cette méthode
protected function _setPassword(string $password) : ?string
{
if (strlen($password) > 0) {
return (new DefaultPasswordHasher())->hash($password);
}
return null;
}
}
Maintenant, rendez-vous sur http://localhost:8765/users pour voir une liste
des utilisateurs existants. N’oubliez pas que votre serveur local doit fonctionner.
Démarrez un serveur PHP autonome utilisant bin/cake server
.
Vous pouvez modifier l’utilisateur par défaut qui a été créé pendant le chapitre Installation du tutoriel. Si vous changez le mot de passe de l’utilisateur, vous devriez voir une version hashée du mot de passe à la place de la valeur par défaut sur l’action index ou view. CakePHP hashe les mots de passe, par défaut, avec bcrypt. Nous recommandons bcrypt pour toutes les nouvelles applications afin de garentir à votre application un niveau de sécurité élevé. C’est l” algorithme de hachage de mot de passe recommandé pour PHP.
Note
Créez maintenant un mot de passe haché pour au moins un des comptes utilisateurs! Il sera nécessaire dans les prochaines étapes. Après avoir mis à jour le mot de passe, vous verrez une longue chaîne stockée dans la colonne du mot de passe. Notez que bcrypt générera un hachage différent même pour le même mot de passe enregistré deux fois.
Il est maintenant temps de configurer le Plugin d’authentification. Le plugin gérera le processus d’authentification en utilisant 3 classes différentes:
Application
utilisera le middleware d’authentification et fournira un
AuthenticationService contenant toute la configuration que nous voulons définir, comment
nous allons vérifier les informations d’identification, et où les trouver.
AuthenticationService
sera une classe utilitaire pour vous permettre de configurer le
processus d’authentification.
AuthenticationMiddleware
sera exécuté dans le cadre de la file d’attente du middleware,
c’est à dire avant que vos contrôleurs ne soient traités par le framework, et collectera les
informations d’identification et les traitera pour vérifier si l’utilisateur est authentifié.
Si vous vous en souvenez, par le passé nous utilisions AuthComponent afin de gérer toutes ces étapes. A présent, la logique est divisée en classes spécifiques et le processus d’authentification se déroule avant votre couche de contrôleur. Il vérifie d’abord si l’utilisateur est authentifié (en fonction de la configuration que vous avez fournie) et injecte l’utilisateur ainsi que le résultat de l’authentification dans la requête afin que vous puissiez les utiliser ultérieurement.
Dans src/Application.php, ajoutez les imports suivants:
// Dans src/Application.php, ajoutez les imports suivants
use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Cake\Routing\Router;
use Psr\Http\Message\ServerRequestInterface;
Ensuite, implémentez l’interface d’authentification pour votre classe Application`
:
// dans src/Application.php
class Application extends BaseApplication
implements AuthenticationServiceProviderInterface
{
Puis ajoutez le code suivant:
// src/Application.php
public function middleware(MiddlewareQueue $middlewareQueue): MiddlewareQueue
{
$middlewareQueue
// ... other middleware added before
->add(new RoutingMiddleware($this))
// add Authentication after RoutingMiddleware
->add(new AuthenticationMiddleware($this));
return $middlewareQueue;
}
public function getAuthenticationService(ServerRequestInterface $request): AuthenticationServiceInterface
{
$authenticationService = new AuthenticationService([
'unauthenticatedRedirect' => Router::url('/users/login'),
'queryParam' => 'redirect',
]);
// Charge les identifiants et s'assure que nous vérifions les champs e-mail et mot de passe
$authenticationService->loadIdentifier('Authentication.Password', [
'fields' => [
'username' => 'email',
'password' => 'password',
]
]);
// Charge les authenticators, nous voulons celui de session en premier
$authenticationService->loadAuthenticator('Authentication.Session');
// Configure la vérification des données du formulaire pour choisir l'email et le mot de passe
$authenticationService->loadAuthenticator('Authentication.Form', [
'fields' => [
'username' => 'email',
'password' => 'password',
],
'loginUrl' => Router::url('/users/login'),
]);
return $authenticationService;
}
Ajoutez le code suivant dans votre classe ``AppController``::
// src/Controller/AppController.php
public function initialize(): void
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadComponent('Flash');
// Ajoutez cette ligne pour vérifier le résultat de l'authentification et verrouiller votre site
$this->loadComponent('Authentication.Authentication');
Désormais, à chaque demande, le AuthenticationMiddleware
inspectera
la session contenue dans la requête afin d’y rechercher un utilisateur authentifié.
Si nous chargeons la page /users/login
, il inspectera également les données de formulaire
soumises (le cas échéant) pour extraire les informations d’identification. Par défaut, les informations
d’identification seront extraites des champs username
and password
dans les données de la demande.
Le résultat de l’authentification sera injecté dans un attribut de requête nommé
authentification
. Vous pouvez consulter le résultat à tout moment en utilisant
$this->request->getAttribute('authentication')
à partir des actions de votre contrôleur.
Toutes vos pages seront restreintes car le AuthenticationComponent
vérifie le
résultat à chaque demande. Lorsqu’il ne parvient pas à trouver un utilisateur authentifié, il redirige
l’utilisateur sur la page /users/login
.
Notez qu’à ce stade, le site ne fonctionnera pas car nous n’avons pas encore de page de connexion.
Si vous visitez votre site, vous obtiendrez une boucle de redirection infinie. Alors, réglons ça !
Dans votre UsersController
, ajoutez le code suivant:
public function beforeFilter(\Cake\Event\EventInterface $event)
{
parent::beforeFilter($event);
// Configurez l'action de connexion pour ne pas exiger d'authentification,
// évitant ainsi le problème de la boucle de redirection infinie
$this->Authentication->addUnauthenticatedActions(['login']);
}
public function login()
{
$this->request->allowMethod(['get', 'post']);
$result = $this->Authentication->getResult();
// indépendamment de POST ou GET, rediriger si l'utilisateur est connecté
if ($result && $result->isValid()) {
// rediriger vers /articles après la connexion réussie
$redirect = $this->request->getQuery('redirect', [
'controller' => 'Articles',
'action' => 'index',
]);
return $this->redirect($redirect);
}
// afficher une erreur si l'utilisateur a soumis un formulaire
// et que l'authentification a échoué
if ($this->request->is('post') && !$result->isValid()) {
$this->Flash->error(__('Votre identifiant ou votre mot de passe est incorrect.'));
}
}
Ajoutez la logique du template pour votre action de connexion:
<!-- dans /templates/Users/login.php -->
<div class="users form">
<?= $this->Flash->render() ?>
<h3>Connexion</h3>
<?= $this->Form->create() ?>
<fieldset>
<legend><?= __('Veuillez s\'il vous plaît entrer votre nom d\'utilisateur et votre mot de passe') ?></legend>
<?= $this->Form->control('email', ['required' => true]) ?>
<?= $this->Form->control('password', ['required' => true]) ?>
</fieldset>
<?= $this->Form->submit(__('Login')); ?>
<?= $this->Form->end() ?>
<?= $this->Html->link("Ajouter un utilisateur", ['action' => 'add']) ?>
</div>
Maintenant, la page de connexion nous permettra de nous connecter correctement à l’application.
Testez-le en affichant n’importe quelle page de votre site. Après avoir été redirigé
à la page /users/login
, saisissez l’email et le mot de passe
choisis lors de la création de votre utilisateur. Vous devriez être redirigé
avec succès après la connexion.
Nous devons ajouter quelques détails supplémentaires pour configurer notre application.
Nous voulons que toutes les pages view
and index
soient accessibles sans connexion,
nous allons donc ajouter cette configuration spécifique dans AppController
// dans src/Controller/AppController.php
public function beforeFilter(\Cake\Event\EventInterface $event)
{
parent::beforeFilter($event);
// pour tous les contrôleurs de notre application, rendre les actions
// index et view publiques, en ignorant la vérification d'authentification
$this->Authentication->addUnauthenticatedActions(['index', 'view']);
}
Note
Si aucun de vos utilisateurs ne possède de mot de passe hashé, commentez le bloc
$this->loadComponent('Authentication.Authentication')
dans votre
AppController ainsi que toutes les autres lignes dans lesquelles le
composant Authenticationest est utilisé. Puis allez à /users/add
Après avoir sauvegardé le mot de passe pour l’utilisateur, décommentez les
lignes que vous venez tout juste de commenter.
Essayez-le en visitant /articles/add
avant de vous connecter! Puisque l’action
n’est pas autorisée, vous serez redirigé vers la page de connexion. Après vous être connecté
avec succès, CakePHP vous redirigera automatiquement vers /articles/add
.
Ajoutez l’action de logout à la classe UsersController
:
// dans src/Controller/UsersController.php
public function logout()
{
$result = $this->Authentication->getResult();
// indépendamment de POST ou GET, rediriger si l'utilisateur est connecté
if ($result && $result->isValid()) {
$this->Authentication->logout();
return $this->redirect(['controller' => 'Users', 'action' => 'login']);
}
}
Vous pouvez maintenant visiter /users/logout
pour vous déconnecter.
Vous devriez alors être envoyé à la page de connexion.
Si vous n’êtes pas connecté et essayez de visiter /users/add, vous serez
redirigé sur la page de connexion. Puisque nous voulons autoriser nos utilisateurs
à créer un compte sur notre application, ajoutez ceci à votre UsersController
:
// Ajoutez la méthode beforeFilter au UsersController
$this->Authentication->addUnauthenticatedActions(['login', 'add']);
Le code ci-dessus indique à AuthenticationComponent
que la méthode add()
du
UsersController
peut être visitée sans être authentifié ou avoir besoin
d’autorisation. Vous pouvez prendre le temps de nettoyer Users/add.php
en retirant les liens qui n’ont plus de sens pour cette page ou passer à la section
suivante. Nous ne nous occuperons pas des actions d’édition, d’affichage ou de liste
spécifiques aux utilisateurs, mais c’est un exercice que vous
pouvez faire par vous-même.
Maintenant que les utilisateurs peuvent se connecter, nous voulons limiter les utilisateurs à modifier uniquement les articles qui ils ont été créés par: doc: application des politiques d’autorisation <./autorisation>.