impulsephp/acl fournit le contrôle d’accès applicatif d’ImpulsePHP. Le package reste volontairement simple : des abilities pour les accès globaux, des policies pour les objets métier, et un middleware pour protéger des zones de l’application sans réinventer le routeur.
- expose un service ACL avec
define(),policy(),can(),canFor(),cannot(),authorize()etauthorizeFor(); - résout automatiquement l’utilisateur courant si
impulsephp/authest présent ; - protège des zones applicatives via un middleware basé sur la configuration ;
- délègue les checks sur objets métier à des classes de policy explicites ;
- fournit un trait léger pour consommer l’ACL depuis pages, composants ou services.
composer require impulsephp/aclLe package déclare son provider via extra.impulse-provider. Si votre application ne gère pas l’auto-découverte, ajoutez Impulse\Acl\AclProvider::class dans providers.
Le provider charge automatiquement un fichier dédié config/acl.php quand il existe dans l’application. Ce fichier peut retourner soit directement la config ACL, soit une clé racine acl.
<?php
use App\Policy\PostPolicy;
use Impulse\Acl\Attributes\Policy;
use Impulse\Acl\AclProvider;
return [
'abilities' => [
'admin.access' => static fn (?object $user): bool => in_array('admin', $user->roles ?? [], true),
],
'role_hierarchy' => [
'admin' => ['manager'],
'manager' => ['editor'],
],
'messages' => [
'forbidden' => 'Vous ne pouvez pas accéder à cette zone.',
'flash_key' => 'acl_error',
],
];Le impulse.php principal peut alors rester léger :
return [
'providers' => [
AclProvider::class,
],
];Options disponibles :
abilitieszones: fallback optionnel par pattern de routerole_hierarchymessages.forbiddenmessages.flash_keypolicies: fallback optionnel si vous ne voulez pas annoter la classe métier
La manière privilégiée pour relier une ressource métier à sa policy est désormais l’attribut :
use App\Policy\PostPolicy;
use Impulse\Acl\Attributes\Policy;
#[Policy(PostPolicy::class)]
final class Post
{
}Le mapping acl.policies reste accepté comme fallback pour des classes externes ou un wiring explicite.
use Impulse\Acl\Contracts\AclInterface;
use Impulse\Core\App;
$acl = App::get(AclInterface::class);
$acl->can('admin.access');
$acl->can('update', $post);
$acl->canFor($user, 'update', $post);
$acl->authorize('admin.access');Quand le provider acl est installé dans l’application principale, core consomme maintenant PageProperty::$roles nativement pendant le routage.
use Impulse\Acl\Middleware\AuthorizeMiddleware;
use Impulse\Auth\Middleware\RequireAuthMiddleware;
use Impulse\Core\Attributes\PageProperty;
use Impulse\Core\Component\AbstractPage;
#[PageProperty(
route: '/admin/users',
roles: ['admin'],
middlewares: [RequireAuthMiddleware::class]
)]
final class AdminUsersPage extends AbstractPage
{
public function template(): string
{
return '<h1>Admin</h1>';
}
}Avec une hiérarchie :
'role_hierarchy' => [
'admin' => ['manager'],
'manager' => ['editor'],
],un utilisateur admin satisfera aussi une page qui demande manager ou editor.
AuthorizeMiddleware reste utile pour le fallback par pattern de chemin avec zones.
Si vous préférez une protection par pattern plutôt que par page, le fallback zones reste disponible :
'zones' => [
'/admin*' => 'admin.access',
],final class PostPolicy
{
public function update(?object $user, Post $post): bool
{
if (!$user instanceof User) {
return false;
}
return $user->role === 'admin' || $user->id === $post->authorId;
}
}Puis :
$acl->can('update', $post);Les refus liés à PageProperty.roles dans core, comme ceux du middleware ACL, utilisent messages.forbidden et poussent aussi un flash sous la clé messages.flash_key.
Le package ne gère jamais l’authentification. Si Impulse\Auth\Contracts\AuthInterface est présent dans le conteneur, Acl l’utilise seulement pour résoudre user() et les rôles du user courant.
Le format historique sous impulse.php['acl'] reste accepté. Le fichier dédié config/acl.php est simplement prioritaire pour mieux cibler la configuration.
use Impulse\Acl\Trait\AuthorizesRequests;
use Impulse\Core\Component\AbstractPage;
final class AccountPage extends AbstractPage
{
use AuthorizesRequests;
public function template(): string
{
if (!$this->can('admin.access')) {
return '<p>Accès limité</p>';
}
return '<p>Administration</p>';
}
}Le package ne gère jamais l’authentification. Si Impulse\Auth\Contracts\AuthInterface est présent dans le conteneur, Acl l’utilise seulement pour résoudre user(). Sinon, les checks implicites se font avec null comme utilisateur courant.
Pour forcer une authentification avant une autorisation, composez les middlewares :
#[PageProperty(
route: '/admin',
middlewares: [
\Impulse\Auth\Middleware\RequireAuthMiddleware::class,
\Impulse\Acl\Middleware\AuthorizeMiddleware::class,
]
)]docs/installation.mddocs/usage.md
php ../core/vendor/bin/phpunit -c phpunit.xml