Volontairement, ce plugin ne gère pas les autorisations. La fonctionnalité a été découplée de l’autorisation dans le but de proposer une séparation des préoccupations claire. Cf. aussi Contrôle d’accès. Ce plugin gère seulement l”identification et l”authentification. On peut avoir un autre plugin pour l’autorisation.
Il n’y a pas de vérification automatique de la session. Pour aller chercher
les informations utilisateur dans la session, vous devrez utiliser le
SessionAuthenticator
. Il va vérifier dans la session s’il y a des données
sous la clé de session configurée, et les place ensuite dans l’objet
Identité.
Les informations sur l’utilisateur ne sont plus disponibles en passant par
l’ancien AuthComponent, mais sont accessibles via un attribut de la requête
et encapsulées dans un objet Identité:
$request->getAttribute('authentication')->getIdentity();
.
En complément, vous pouvez exploiter les méthodes getIdentity()
ou
getIdentityData()
de AuthenticationComponent
.
La logique du processus d’authentification a été scindée en authentificateurs et identificateurs. Un authentificateur va extraire les identifiants de l’utilisateur (credentials) dans la requête, tandis que les identificateurs les vérifieront et désigneront l’utilisateur correspondant.
DigestAuthenticate a été renommé en HttpDigestAuthenticator.
BasicAuthenticate a été renommé en HttpBasicAuthenticator.
Tous les adaptateurs d’authentification existants, Form, Basic, Digest sont toujours là mais ont été remodelés en authentificateurs.
Suivant en cela le principe de séparation des préoccupations, les anciens objets d’authentification ont été scindés en objets bien séparés, les identificateurs et les authentificateurs.
Les authentificateurs prennent la requête entrante et tentent d’en extraire les identifiants de l’utilisateur. S’ils les trouvent, ils les passent à une collection d’identificateurs qui recherchent où se trouve l’utilisateur. Pour cette raison, les authentificateurs prennent une IdentifierCollection en premier argument dans leur constructeur.
Les identificateurs confrontent les identifiants à un système de stockage (par exemple des tables ORM, LDAP, etc) et renvoient les informations de l’utilisateur identifié.
Cela facilite le changement de logique d’identification en tant que de besoin, ou l’utilisation de plusieurs sources d’informations sur les utilisateurs.
Si vous voulez implémenter vos propres identificateurs, votre identificateur
doit implémenter l’interface IdentifierInterface
.
La première chose à faire pour migrer votre application est de charger le plugin authentication dans la méthode bootstrap de votre application:
public function bootstrap(): void
{
parent::bootstrap();
$this->addPlugin('Authentication');
}
Ensuite, modifiez votre application pour lui faire implémenter l’interface de fournisseur de service d’authentification. Cela permet à votre AuthenticationMiddleware de savoir comment obtenir un service d’authentification à partir de votre application:
// dans src/Application.php
// Ajoutez les instructions 'use' suivantes.
use Authentication\AuthenticationService;
use Authentication\AuthenticationServiceInterface;
use Authentication\AuthenticationServiceProviderInterface;
use Authentication\Middleware\AuthenticationMiddleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
// Ajoutez l'interface d'authentification.
class Application extends BaseApplication implements AuthenticationServiceProviderInterface
{
/**
* Renvoie une instance du service provider.
*
* @param \Psr\Http\Message\ServerRequestInterface $request Request
* @param \Psr\Http\Message\ResponseInterface $response Response
* @return \Authentication\AuthenticationServiceInterface
*/
public function getAuthenticationService(ServerRequestInterface $request) : AuthenticationServiceInterface
{
$service = new AuthenticationService();
// Configurez le service. (cf. ci-dessous pour les détails)
return $service;
}
}
Puis ajoutez l”AuthenticationMiddleware
à votre application:
// dans src/Application.php
public function middleware($middlewareQueue)
{
// Divers autres middlewares pour la gestion des erreurs, le routing, etc, sont ajoutés ici.
// Ajoutez le middleware à la middleware queue
$middlewareQueue->add(new AuthenticationMiddleware($this));
return $middlewareQueue;
}
Le tableau de configuration de AuthComponent
a besoin d’être scindé en
identificateurs et authentificateurs lors de la configuration du service. Ainsi,
si votre AuthComponent
était configuré de cette façon:
$this->loadComponent('Auth', [
'authentication' => [
'Form' => [
'fields' => [
'username' => 'email',
'password' => 'password',
]
]
]
]);
Vous devrez maintenant le configurer de cette façon:
// Instancier le service
$service = new AuthenticationService();
// Charger les identificateurs
$service->loadIdentifier('Authentication.Password', [
'fields' => [
'username' => 'email',
'password' => 'password',
]
]);
// Charger les authentificateurs
$service->loadAuthenticator('Authentication.Session');
$service->loadAuthenticator('Authentication.Form');
Si vous aviez personnalisé le userModel
, vous pouvez utiliser la
configuration suivante:
// Instancier le service
$service = new AuthenticationService();
// Charger les identificateurs
$service->loadIdentifier('Authentication.Password', [
'resolver' => [
'className' => 'Authentication.Orm',
'userModel' => 'Employes',
],
'fields' => [
'username' => 'email',
'password' => 'password',
]
]);
Bien qu’il y ait un petit peu plus de code qu’avant, vous avez plus de souplesse dans la gestion des authentifications.
L”AuthenticationMiddleware
va se charger de la vérification et de la
définition de l’identité de l’utilisateur en s’appuyant sur les
authentificateurs. D’habitude, après la connexion, AuthComponent
redirigeait
vers une URL définie dans la configuration. Pour rediriger après une connexion
réussie, changez votre action login pour vérifier le résultat de la nouvelle
identité:
public function login()
{
$result = $this->Authentication->getResult();
// Que l'on soit en POST ou GET, rediriger l'utilisateur s'il est connecté
if ($result->isValid()) {
$target = $this->Authentication->getLoginRedirect();
return $this->redirect($target);
}
// Afficher une erreur si l'utilisateur a validé le formulaire et que
// l'authentification a échoué
if ($this->request->is(['post'])) {
$this->Flash->error('Identifiant ou mot de passe invalide');
}
}
Après avoir appliqué le middleware vous pouvez utiliser les données d’identité
en consultant l’attribut identity
de la requête. Cela remplace les appels à
$this->Auth->user()
que vous utilisiez jusqu’à présent. Si l’utilisateur en
cours n’est pas authentifié ou si les identifiants fournis étaient invalides,
l’attribut identity
sera null
:
$user = $request->getAttribute('identity');
Pour plus de détails sur le résultat du processus d’authentification, vous
pouvez accéder à l’objet Résultat qui est aussi fourni dans la requête et est
accessible sous l’attribut authentication
:
$result = $request->getAttribute('authentication')->getResult();
// Booléen si le résultat est valide
$isValid = $result->isValid();
// Un code de statut
$statusCode = $result->getStatus();
// Un tableau de messages d'erreur, ou des données si l'identificateur en a fournies
$errors = $result->getErrors();
À chaque endroit où vous appeliez AuthComponent::setUser()
, vous devriez à
présent utiliser setIdentity()
:
// Supposons que vous ayez besoin de rechercher un utilisateur à partir d'un jeton d'accès
$user = $this->Users->find('byToken', ['token' => $token])->first();
// Rendre l'utilisateur persistant dans les authentificateurs configurés.
$this->Authentication->setIdentity($user);
Comme AuthComponent
, l”AuthenticationComponent
rend aisé le marquage
d’actions spécifiques comme étant “publiques” et ne nécessitant pas la présence
d’une identité valide:
// Dans la méthode beforeFilter de votre contrôleur.
$this->Authentication->allowUnauthenticated(['view']);
Chaque appel à allowUnauthenticated()
écrasera la liste d’actions en cours.
Par défaut, AuthComponent
renvoie les utilisateurs vers la page de connexion
lorsqu’une authentification est exigée. Au contraire, dans ce scénario,
l”AuthenticationComponent
de ce plugin soulèvera une exception. Vous
pouvez convertir cette exception en redirection en utilisant
unauthenticatedRedirect
dans la configuration de
l”AuthenticationService
.
Vous pouvez aussi passer l’URI ciblée par la requête en cours en tant que
paramètre dans la query string de la redirection avec l’option queryParam
:
// Dans la méthode getAuthenticationService() de votre src/Application.php
$service = new AuthenticationService();
// Configurer la redirection en cas de non authentification
$service->setConfig([
'unauthenticatedRedirect' => '/users/login',
'queryParam' => 'redirect',
]);
Puis, dans la méthode login de votre contrôleur, vous pouvez utiliser en toute
sécurité getLoginRedirect()
pour obtenir la cible redirigée, à partir du
paramètre de la query string:
public function login()
{
$result = $this->Authentication->getResult();
// Que l'on soit en POST ou GET, rediriger l'utilisateur s'il est connecté
if ($result->isValid()) {
// Utiliser le paramètre de redirection s'il est présent.
$target = $this->Authentication->getLoginRedirect();
if (!$target) {
$target = ['controller' => 'Pages', 'action' => 'display', 'home'];
}
return $this->redirect($target);
}
}
Si votre application utilise la fonctionnalité de AuthComponent
de mise à
niveau du hachage. Vous pouvez répliquer cette logique dans ce plugin en tirant
parti de l”AuthenticationService
:
public function login()
{
$result = $this->Authentication->getResult();
// Que l'on soit en POST ou GET, rediriger l'utilisateur s'il est connecté
if ($result->isValid()) {
$authService = $this->Authentication->getAuthenticationService();
// En supposant que vous utilisez l'identificateur `Password`.
if ($authService->identifiers()->get('Password')->needsPasswordRehash()) {
// Le re-hachage se produit lors de la sauvegarde.
$user = $this->Users->get($this->Authentication->getIdentityData('id'));
$user->password = $this->request->getData('password');
$this->Users->save($user);
}
// Rediriger vers une page connectée
return $this->redirect([
'controller' => 'Pages',
'action' => 'display',
'home'
]);
}
}