RBAC - Système complet de permissions (Backend + Frontend) #7
Reference in New Issue
Block a user
Delete Branch "feat/rbac-admin-users"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Résumé
Implémentation complète du système RBAC (Role-Based Access Control) pour Coltura.
Backend
PATCH /users/{id}/rbacpour assigner rôles, permissions directes et isAdminapp:sync-permissionspour synchroniser les permissions déclarées par les modulespermissionkey optionnelle dans sidebar.php)Frontend
usePermissions()aveccan(),canAny(),canAll()et admin bypass/admin/roles: DataTable, création/édition via drawer, suppression avec confirmation/admin/users: DataTable, drawer RBAC avec rôles, permissions directes, résumé effectifPermissions déclarées
core.users.view— Voir les utilisateurscore.users.manage— Gérer les utilisateurscore.roles.view— Voir les rôles RBACcore.roles.manage— Gérer les rôles et permissionsGET /api/permissionsaccessible à tout utilisateur authentifié (catalogue read-only)Tickets Lesstime
Test plan
make db-resetpuis vérifier les fixtures (admin/alice/bob, rôles système)make test: 115 tests PHPUnit passentcd frontend && npm run test: tests Vitest passent🤖 Generated with Claude Code
- Expose l'entite Permission via ApiResource (GetCollection + Get uniquement) - Serialisation limitee au groupe permission:read (id, code, label, module, orphan) - Securite temporaire is_granted('ROLE_ADMIN'), a remplacer par is_granted('core.permissions.view') au ticket #345 - Filtres : SearchFilter exact sur module, BooleanFilter sur orphan - Configure api_platform.mapping.paths pour que le compile pass AP decouvre les ApiResource/ApiFilter declares dans src/Module/Core/Domain/Entity - Ajoute symfony/browser-kit et symfony/http-client en dev pour les tests fonctionnels API Platform, plus KERNEL_CLASS dans phpunit.dist.xml - Tests fonctionnels PermissionApiTest : collection, get item, filtres module et orphan, 405 sur POST, 401 non authentifie, 403 non-adminAjoute une operation Patch dediee `PATCH /api/users/{id}/rbac` (nom `user_rbac_patch`) qui accepte exclusivement les champs RBAC isAdmin, roles et directPermissions via le groupe user:rbac:write. L'endpoint est separe volontairement du Patch profil existant pour isoler la modification des droits de celle des donnees profil (decision0fc4e16). UserRbacProcessor delegue au PersistProcessor Doctrine decore et applique une garde auto-suicide : un admin ne peut pas retirer ses propres droits administrateur (compare l'etat entrant a l'etat UnitOfWork). La garde 'dernier admin' globale est reportee au ticket #345. La propriete Doctrine $roles est renommee $rbacRoles pour eviter la collision avec UserInterface::getRoles() (qui renvoie list<string>) lors de la normalization API Platform. La cle JSON reste `roles` grace a SerializedName, le contrat API est inchange. Tests : 6 unitaires (UserRbacProcessorTest) + 8 fonctionnels (UserRbacApiTest) couvrant promotion admin, remplacement des collections roles/directPermissions, 401/403, filtrage du groupe denormalization (`username` ignore), preservation de isAdmin sur le Patch profil, et garde auto-suicide.Introduit AdminHeadcountGuardInterface pour permettre le mock en tests unitaires, puis cree UserProcessor qui protege DELETE /api/users/{id} contre la suppression du dernier administrateur via la garde domaine.- Ajoute #[Groups(['me:read'])] sur getEffectivePermissions() dans User.php - Fixe la serialisation de isAdmin : le prefixe "is" etait strip par Symfony, expose desormais via le getter avec #[SerializedName('isAdmin')] + groups lecture, la propriete conserve uniquement le groupe d'ecriture user:rbac:write - Cree MeApiTest avec 4 tests fonctionnels (isAdmin admin, permissions vides user, 401 sans auth, effectivePermissions avec role portant une permission)