Le plugin Authorization s’intègre dans votre application en tant que middleware.
Le AuthorizationMiddleware
assume les responsablités suivantes:
Décorer l”“identity” de la requête avec un décorateur qui ajoute les méthodes
can
, canResult
, et applyScope
si nécessaire.
S’assurer que l’autorisation a été vérifiée ou contournée dans la requête.
Pour utiliser le middleware, implémentez
AuthorizationServiceProviderInterface
dans votre classe d’application. Puis
passez votre instance d’application au middleware et ajoutez le middleware à la
middleware queue.
Voici un exemple basique:
namespace App;
use Authorization\AuthorizationService;
use Authorization\AuthorizationServiceProviderInterface;
use Authorization\Middleware\AuthorizationMiddleware;
use Authorization\Policy\OrmResolver;
use Cake\Http\BaseApplication;
class Application extends BaseApplication implements AuthorizationServiceProviderInterface
{
public function getAuthorizationService(ServerRequestInterface $request, ResponseInterface $response)
{
$resolver = new OrmResolver();
return new AuthorizationService($resolver);
}
public function middleware($middlewareQueue)
{
// autres middlewares
$middlewareQueue->add(new AuthorizationMiddleware($this));
return $middlewareQueue;
}
}
Le service d’autorisation a besoin d’un résolveur de policy. Pour savoir quels sont les résolveurs disponibles et comment les utiliser, consultez la documentation des Policies.
Par défaut, l”identity
dans une requête sera décorée (envelopée) par
Authorization\IdentityDecorator
. La classe du décorateur intercepte les
appels aux méthodes, les accès à la manière des tableaux et les accès aux
propriétés vers l’objet décoré. Utilisez getOriginalData()
pour accéder
directement à l’objet sous-jacent:
$originalUser = $user->getOriginalData();
Si votre application utilise le plugin cakephp/authentication alors c’est la classe
Authorization\Identity
qui sera utilisée. Cette classe implémente
Authentication\IdentityInterface
en plus de
Authorization\IdentityInterface
. Cela vous permet d’utiliser le component et
le helper des bibliothèques de Authentication
pour obtenir l’identity
décorée.
Si vous avez déjà une classe User
ou une classe d’identité, vous pouvez vous
passer du décorateur en implémentant Authorization\IdentityInterface
et en
utilisant l’option identityDecorator
du middleware. Pour commencer, mettons
à jour notre classe User
:
namespace App\Model\Entity;
use Authorization\AuthorizationServiceInterface;
use Authorization\IdentityInterface;
use Authorization\Policy\ResultInterface;
use Cake\ORM\Entity;
class User extends Entity implements IdentityInterface
{
/**
* @inheritDoc
*/
public function can(string $action, mixed $resource): bool
{
return $this->authorization->can($this, $action, $resource);
}
/**
* @inheritDoc
*/
public function canResult(string $action, mixed $resource): ResultInterface
{
return $this->authorization->canResult($this, $action, $resource);
}
/**
* @inheritDoc
*/
public function applyScope(string $action, mixed $resource, mixed ...$optionalArgs): mixed
{
return $this->authorization->applyScope($this, $action, $resource, ...$optionalArgs);
}
/**
* @inheritDoc
*/
public function getOriginalData(): \ArrayAccess|array
{
return $this;
}
/**
* Setter to be used by the middleware.
*/
public function setAuthorization(AuthorizationServiceInterface $service)
{
$this->authorization = $service;
return $this;
}
// Autres méthodes
}
Maintenant que votre user implémente l’interface nécessaire, mettons à jour la configuration de notre middleware:
// Dans votre méthode Application::middleware()
// Authorization
$middlewareQueue->add(new AuthorizationMiddleware($this, [
'identityDecorator' => function ($auth, $user) {
return $user->setAuthorization($auth);
}
]));
Vous n’avez plus à changer les typehints, et vous pouvez commencer à utiliser les policies d’autorisation partout où vous avez accès à votre user.
Si vous utilisez aussi le plugin Authentication, assurez-vous d’implémenter les deux interfaces.:
use Authorization\IdentityInterface as AuthorizationIdentity;
use Authentication\IdentityInterface as AuthenticationIdentity;
class User extends Entity implements AuthorizationIdentity, AuthenticationIdentity
{
...
/**
* Méthode Authentication\IdentityInterface
*
* @return string
*/
public function getIdentifier()
{
return $this->id;
}
...
}
Par défaut, le AuthorizationMiddleware
s’assurera que chaque requête
contenant une identity
a aussi passé ou contourné l’autorisation d’accès. Si
l’autorisation d’accès n’est pas vérifiée, il soulèvera une
AuthorizationRequiredException
.
Cette exception est soulevée après la fin des actions de votre
middleware/controller, donc vous ne pouvez pas vous y fier pour prévenir des
accès non autorisés. Toutefois cela peut être une aide utile pendant le
développement et les tests. Vous pouvez désactiver ce comportement grâce à une
option:
$middlewareQueue->add(new AuthorizationMiddleware($this, [
'requireAuthorizationCheck' => false
]));
Par défaut, le middleware fait suivre les exceptions d’autorisation lancées par l’application. Vous pouvez configurer des gestionnaires pour les requêtes non autorisées et exécuter une action personnalisée, par exemple rediriger l’utilisateur vers la page de connexion.
Les gestionnaires intégrés sont:
Exception
- ce gestionnaire fera suivre l’exception, c’est le comportement
par défaut du middleware.
Redirect
- ce gestionnaire redirigera la requête vers l’URL indiquée.
CakeRedirect
- gestionnaire de redirection supportant le Router CakePHP.
Les deux gestionnaires de redirection partagent les mêmes options de configuration:
url
- URL vers laquelle rediriger (CakeRedirect
supporte la syntaxe du
Router CakePHP).
exceptions
- une liste de classes d’exceptions à rediriger. Par défaut
seule MissingIdentityException
est redirigée.
queryParam
- l’URL à laquelle la requête a tenté d’accéder sera attachée
à un paramètre query de l’URL de redirection (par défaut redirect
).
statusCode
- le code de statut HTTP d’une redirection, par défaut 302
.
Par exemple:
use Authorization\Exception\MissingIdentityException;
$middlewareQueue->add(new AuthorizationMiddleware($this, [
'unauthorizedHandler' => [
'className' => 'Authorization.Redirect',
'url' => '/pages/accesinterdit',
'queryParam' => 'redirectUrl',
'exceptions' => [
MissingIdentityException::class,
OtherException::class,
],
],
]));
Tous les gestionnaires prennent comme paramètre l’exception qui a été soulevée.
Cette exception sera toujours une instance de
Authorization\Exception\Exception
.
Dans cet exemple, le gestionnaire Authorization.Redirect
vous permet
simplement de préciser quelles exceptions vous souhaitez écouter.
Ainsi, dans cet exemple où nous utilisons le gestionnaire
Authorization.Redirect
, nous pouvons ajouter au tableau exceptions
d’autres exceptions basées sur Authorization\Exception\Exception
si nous
voulons qu’elles soient traitées convenablement:
'exceptions' => [
MissingIdentityException::class,
ForbiddenException::class
],
Consultez la source de RedirectHandler
Les options de configuration sont passées à la méthode handle()
du
gestionnaire comme dernier paramètre.
Pour l’instant, il n’y a pas de moyen idéal pour ajouter un message flash lors d’une redirection suite à une requête non autorisée.
Par conséquent vous devez créer votre propre Handler, qui ajoutera le message flash (ou toute autre logique que vous voudriez exécuter lors d’une redirection).
Comment créer un UnauthorizedHandler personnalisé¶
Créez le fichier
src/Middleware/UnauthorizedHandler/CustomRedirectHandler.php
:Dites au AuthorizationMiddleware d’utiliser votre nouveau Handler personnalisé:
Comme vous le voyez, vous pouvez conserver la même configuration que si vous utilisiez le nom de classe
Authorization.Redirect
.Cela est dû au fait que notre Handler étend le RedirectHandler présent dans le plugin. Ainsi, il contient toutes les fonctionnalités d’origin + notre propre logique dans la fonction
handle()
.Le
custom_param
apparaît dans le tableau$options
qui vous sera donné dans la fonctionhandle()
à l’intérieur de votreCustomRedirectHandler
si vous souhaitez ajouter quelques paramètres de configuration supplémentaires à vos fonctionnalités personnalisées.Vous pouvez consulter les classes CakeRedirectHandler ou RedirectHandler pour voir à quoi un Handler pourrait/devrait ressembler.