@fickou/adonis-access-control-list
v2.0.9
Published
Help dev to filter database with query parameters
Maintainers
Readme
adonis-access-control-list
Add Access Control List (ACL) for Adonis JS 5+
Table of contents
- Installation
- Configuration
- Models Setup
- Working With Roles
- Working With Permissions
- User Helper Methods
- Wildcard Permissions
- Super Admin Role
- Soft Delete Support
- CLI Commands
- Protect Routes
- Testing
Installation
1. Install Package
npm i --save @fickou/adonis-access-control-list2. Install Soft Delete Dependency
npm i --save adonis-lucid-soft-deletes@^1.4.43. Configure Provider
node ace configure @fickou/adonis-access-control-list4. Setup Migrations
node ace acl:setup5. Run Migrations
node ace migration:runConfiguration
Allez dans config/acl.ts pour personnaliser votre configuration :
import { ConfigAclContract } from "@ioc:Adonis/Addons/Acl";
const configAcl: ConfigAclContract = {
/**
* Préfixe pour les routes ACL de gestion
*/
prefix: "acl",
/**
* Middlewares appliqués aux routes de gestion
* undefined = pas de middleware (à configurer par l'utilisateur)
*/
middlewares: undefined,
/**
* Noms des tables de jointure
*/
joinTables: {
permissionRole: "permission_role",
permissionUser: "permission_user",
userRole: "user_role",
},
/**
* Mode API uniquement (pas de routes web de gestion)
* Recommandé: true pour les applications API pures
*/
apiOnly: true,
/**
* Slug du rôle super admin qui bypass toutes les permissions
*/
superAdminRole: "super_admin",
};
export default configAcl;Models Setup
1. Enregistrer le Middleware
Dans start/kernel.ts :
Server.middleware.register([
() => import('@ioc:Adonis/Core/BodyParser'),
() => import('App/Middleware/Auth'),
() => import('@ioc:Adonis/Addons/Acl/Authorize'), // ✅ Ajoutez cette ligne
])2. Configurer le Modèle User
Dans app/Models/User.ts, composez votre modèle avec BaseUser :
import { BaseModel, column } from '@ioc:Adonis/Lucid/Orm'
import { compose } from '@poppinss/utils/build/src/Helpers'
import BaseUser from '@ioc:Adonis/Addons/Acl/BaseUser'
export default class User extends compose(BaseModel, BaseUser) {
@column({ isPrimary: true })
public id: number
@column()
public name: string
@column()
public email: string
@column({ serializeAs: null })
public password: string
}Working With Roles
Créer un Rôle
Via le modèle
import Role from '@ioc:Adonis/Addons/Acl/Models/Role'
const roleAdmin = new Role()
roleAdmin.name = 'Administrator'
roleAdmin.slug = 'admin'
roleAdmin.description = 'Gestion des privilèges administrateur'
await roleAdmin.save()Via CLI
node ace acl:create:role admin Administrator --description="Administrateur système"Assigner un Rôle à un Utilisateur
Via les relations
const user = await User.find(1)
await user.related('roles').attach([roleAdmin.id])Via CLI
node ace acl:assign:role admin 1Retirer un Rôle
const user = await User.find(1)
await user.related('roles').detach([roleAdmin.id])Lister les Rôles
node ace acl:list:rolesRécupérer les Rôles d'un Utilisateur
const user = await User.find(1)
const roles = await user.getRoles() // ['admin', 'moderator']Working With Permissions
Créer une Permission
Via le modèle
import Permission from '@ioc:Adonis/Addons/Acl/Models/Permission'
const createUsersPermission = new Permission()
createUsersPermission.slug = 'users.create'
createUsersPermission.name = 'Create Users'
createUsersPermission.description = 'Créer des utilisateurs'
createUsersPermission.group = 'users'
createUsersPermission.route = 'POST /users'
await createUsersPermission.save()Via CLI
node ace acl:create:permission users.create "Create Users" \
--description="Créer des utilisateurs" \
--group="users" \
--route="POST /users"Synchroniser depuis les Routes
node ace acl:store:accessCette commande scanne toutes vos routes avec .access() et crée/met à jour automatiquement les permissions.
Assigner des Permissions à un Rôle
Via les relations
const roleAdmin = await Role.find(1)
await roleAdmin.related('permissions').attach([permission.id])Via CLI
node ace acl:assign:permission users.create --role=adminAssigner des Permissions à un Utilisateur
Via les relations
const user = await User.find(1)
await user.related('permissions').attach([permission.id])Via CLI
node ace acl:assign:permission users.create --user=1Lister les Permissions
# Toutes les permissions
node ace acl:list:permissions
# Filtrer par groupe
node ace acl:list:permissions --group=usersRécupérer les Permissions d'un Utilisateur
const user = await User.find(1)
const permissions = await user.getAccesses()
// ['users.create', 'users.update', 'users.delete', 'posts.*']User Helper Methods
Le mixin BaseUser ajoute plusieurs méthodes utiles à votre modèle User :
const user = await User.find(1)
// Vérifier un rôle
await user.hasRole('admin') // true/false
// Vérifier plusieurs rôles (au moins un)
await user.hasAnyRole(['admin', 'moderator']) // true si l'un des rôles
// Vérifier plusieurs rôles (tous requis)
await user.hasAllRoles(['admin', 'moderator']) // true si tous les rôles
// Vérifier une permission
await user.hasPermission('users.create') // true/false
// Vérifier plusieurs permissions (au moins une)
await user.hasAnyPermission(['users.create', 'users.update'])
// Vérifier plusieurs permissions (toutes requises)
await user.hasAllPermissions(['users.create', 'users.update'])
// Vérifier si super admin
await user.isSuperAdmin() // true/false
// Vérifier une permission (alias)
await user.can('users.create') // true/false
// Charger les permissions en cache
await user.loadPermissions()Wildcard Permissions
Les permissions supportent les patterns wildcard :
// Permission wildcard
const permission = new Permission()
permission.slug = 'users.*'
permission.name = 'All User Permissions'
await permission.save()
// Assigner à un rôle
const role = await Role.findBy('slug', 'admin')
await role.related('permissions').attach([permission.id])
// Maintenant l'utilisateur avec ce rôle a accès à :
// ✅ users.create
// ✅ users.update
// ✅ users.delete
// ✅ users.show
// ❌ posts.create (différent préfixe)
// Permission super wildcard
permission.slug = '*' // Accès à TOUTExemples de patterns :
*→ Toutes les permissionsusers.*→ Toutes les permissions users (users.create, users.update, etc.)posts.*→ Toutes les permissions postsusers.create→ Permission exacte uniquement
Super Admin Role
Le rôle configuré comme superAdminRole dans la config bypass automatiquement toutes les vérifications de permissions.
// config/acl.ts
superAdminRole: "super_admin"// Créer le rôle super admin
const superAdmin = new Role()
superAdmin.slug = 'super_admin'
superAdmin.name = 'Super Administrator'
await superAdmin.save()
// Assigner à un utilisateur
const user = await User.find(1)
await user.related('roles').attach([superAdmin.id])
// Cet utilisateur a maintenant accès à TOUT
// sans avoir besoin d'assigner de permissionsSoft Delete Support
Les rôles et permissions utilisent le soft delete. Les enregistrements supprimés restent en base avec deleted_at non null.
Comportement automatique
Si vous essayez de créer un rôle/permission qui existe déjà en soft-deleted :
- ✅ L'ancien enregistrement est automatiquement restauré et mis à jour
- ❌ Pas d'erreur de clé dupliquée
// 1. Créer une permission
const perm = await Permission.create({ slug: 'users.create', name: 'Create' })
// 2. La supprimer (soft delete)
await perm.delete()
// 3. La recréer → Restauration automatique !
const newPerm = await Permission.create({ slug: 'users.create', name: 'Create Users' })
// newPerm.id === perm.id (même enregistrement restauré)Gestion manuelle
// Afficher seulement les éléments supprimés
const trashedPermissions = await Permission.query().onlyTrashed()
// Restaurer
const permission = await Permission.query()
.withTrashed()
.where('id', 1)
.first()
await permission.restore()
// Supprimer définitivement
await permission.forceDelete()CLI Commands
Gestion des Rôles
# Créer un rôle
node ace acl:create:role <slug> <name> [--description]
# Exemples
node ace acl:create:role admin Administrator
node ace acl:create:role moderator Moderator --description="Modération du contenu"
# Lister tous les rôles
node ace acl:list:roles
# Assigner un rôle à un utilisateur
node ace acl:assign:role <role-slug> <user-id>
node ace acl:assign:role admin 1Gestion des Permissions
# Créer une permission
node ace acl:create:permission <slug> <name> [options]
# Exemples
node ace acl:create:permission users.create "Create Users"
node ace acl:create:permission users.update "Update Users" \
--description="Modifier les utilisateurs" \
--group="users" \
--route="PUT /users/:id"
# Lister toutes les permissions
node ace acl:list:permissions
# Lister par groupe
node ace acl:list:permissions --group=users
# Assigner une permission à un rôle
node ace acl:assign:permission <permission-slug> --role=<role-slug>
node ace acl:assign:permission users.create --role=admin
# Assigner une permission à un utilisateur
node ace acl:assign:permission <permission-slug> --user=<user-id>
node ace acl:assign:permission users.create --user=1Synchronisation des Routes
# Synchroniser les permissions depuis les routes définies
node ace acl:store:accessProtect Routes
Protégez vos routes avec le middleware et la méthode .access() :
import Route from '@ioc:Adonis/Core/Route'
Route.group(() => {
// Définir les permissions pour chaque route
Route.get('users', 'UsersController.index')
.access('users.list', 'Liste des utilisateurs')
Route.get('users/:id', 'UsersController.show')
.access('users.show', 'Détail utilisateur')
Route.post('users', 'UsersController.store')
.access('users.create', 'Créer un utilisateur')
Route.put('users/:id', 'UsersController.update')
.access('users.update', 'Modifier un utilisateur')
Route.delete('users/:id', 'UsersController.destroy')
.access('users.delete', 'Supprimer un utilisateur')
}).prefix('api/v1').middleware('auth')
// Puis synchroniser
// $ node ace acl:store:accessVérifications Manuelles
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'
export default class UsersController {
public async index({ auth, response }: HttpContextContract) {
const user = auth.user!
// Vérifier une permission
if (!(await user.can('users.list'))) {
return response.forbidden({ message: 'Accès refusé' })
}
// Vérifier un rôle
if (!(await user.hasRole('admin'))) {
return response.forbidden({ message: 'Admin requis' })
}
// Votre logique
}
}Testing
Ce package est livré avec une suite de tests complète. Pour exécuter les tests, clonez le dépôt et exécutez la commande suivante :
npm test