impulsephp / acl
Lightweight access control provider for ImpulsePHP with abilities, policies and middleware integration.
Requires
- php: >=8.2
- impulsephp/core: dev-main
Requires (Dev)
- phpunit/phpunit: ^12.2
Suggests
- impulsephp/auth: Recommended to resolve the current authenticated user automatically during ACL checks.
- impulsephp/ui: Useful to consume ACL checks directly from pages and UI components.
This package is auto-updated.
Last update: 2026-04-11 17:00:02 UTC
README
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.
Ce que fait le package
- 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.
Installation
composer require impulsephp/acl
Le 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.
Configuration dédiée
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
Policies via attribut PHP 8
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.
API principale
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');
Protéger une page avec PageProperty.roles
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.
Fallback par ability de zone
Si vous préférez une protection par pattern plutôt que par page, le fallback zones reste disponible :
'zones' => [ '/admin*' => 'admin.access', ],
Policies pour les objets métier
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);
Messages d’erreur
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.
Intégration avec auth
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.
Ancien exemple de configuration
Le format historique sous impulse.php['acl'] reste accepté. Le fichier dédié config/acl.php est simplement prioritaire pour mieux cibler la configuration.
Utilisation depuis une page ou un composant
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>'; } }
Intégration avec auth
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,
]
)]
Documentation
docs/installation.mddocs/usage.md
Tests
php ../core/vendor/bin/phpunit -c phpunit.xml