@un-dev-suisse/nestjs-permissions
v1.1.2
Published
NestJS Permissions Service - A simple permissions service for NestJS applications
Downloads
44
Maintainers
Readme
@un-dev-suisse/nestjs-permissions
Un service de permissions robuste pour les applications NestJS avec gestion d'erreurs avancée.
Installation
npm install @un-dev-suisse/nestjs-permissionsor
pnpm install @un-dev-suisse/nestjs-permissionsUtilisation
1. Importer le module
import { Module } from '@nestjs/common';
import { PermissionsModule } from '@un-dev-suisse/nestjs-permissions';
@Module({
imports: [PermissionsModule],
})
export class AppModule {}2. Utiliser le service
import { Injectable } from '@nestjs/common';
import {
PermissionCheckerService,
UserPermissions,
UnsupportedHttpMethodException,
InvalidPermissionFormatException,
InsufficientPermissionException
} from '@un-dev-suisse/nestjs-permissions';
@Injectable()
export class MyService {
constructor(private readonly permissionService: PermissionCheckerService) {}
async checkUserAccess(userPermissions: UserPermissions, resource: string) {
try {
// Vérifier une permission spécifique
const hasAccess = this.permissionService.checkPermission(
userPermissions,
`${resource}:read`
);
if (!hasAccess) {
throw new InsufficientPermissionException(`${resource}:read`);
}
return true;
} catch (error) {
if (error instanceof InvalidPermissionFormatException) {
console.error('Format de permission invalide:', error.message);
} else if (error instanceof InsufficientPermissionException) {
console.error('Permission insuffisante:', error.message);
}
throw error;
}
}
async checkMultiplePermissions(userPermissions: UserPermissions) {
const requiredPermissions = [
'users:read',
'users:create',
'posts:read'
];
try {
// Vérifier toutes les permissions
const hasAllPermissions = this.permissionService.checkMultiplePermissions(
userPermissions,
requiredPermissions
);
// Vérifier au moins une permission
const hasAnyPermission = this.permissionService.checkAnyPermission(
userPermissions,
['admin:all', 'moderator:read']
);
return { hasAllPermissions, hasAnyPermission };
} catch (error) {
console.error('Erreur de vérification des permissions:', error.message);
throw error;
}
}
getPermissionFromHttpMethod(method: string) {
try {
return this.permissionService.getPermissionFromMethod(method);
} catch (error) {
if (error instanceof UnsupportedHttpMethodException) {
console.error('Méthode HTTP non supportée:', error.message);
}
throw error;
}
}
}Gestion des exceptions
Le service fournit des exceptions spécifiques pour différents cas d'erreur. Toutes les exceptions sont utilisées directement avec leurs constructeurs :
Utilisation directe des exceptions
// ✅ Correct - Utilisation directe
throw new InvalidPermissionFormatException('users:invalid');
throw new InsufficientPermissionException('admin:all');
throw new UnsupportedHttpMethodException('INVALID');
// ❌ Incorrect - Pas de classe utilitaire
// throw PermissionExceptions.invalidFormat('users:invalid');Exceptions disponibles
UnsupportedHttpMethodException: Méthode HTTP non supportéeInvalidPermissionFormatException: Format de permission invalideMissingPermissionComponentException: Ressource ou action manquanteInvalidPermissionActionException: Action de permission invalideInvalidUserPermissionsException: Permissions utilisateur invalidesInsufficientPermissionException: Permission insuffisanteResourcePermissionNotFoundException: Ressource non trouvéeDefaultPermissionNotConfiguredException: Permissions par défaut non configuréesInvalidPermissionMaskException: Masque de permission invalideEmptyPermissionListException: Liste de permissions vide
Exemples d'utilisation des exceptions
import {
UnsupportedHttpMethodException,
InvalidPermissionFormatException,
MissingPermissionComponentException,
InvalidPermissionActionException,
InvalidUserPermissionsException,
InsufficientPermissionException,
EmptyPermissionListException
} from '@un-dev-suisse/nestjs-permissions';
// Validation des méthodes HTTP
try {
const permission = service.getPermissionFromMethod('INVALID');
} catch (error) {
if (error instanceof UnsupportedHttpMethodException) {
console.error('Méthode non supportée:', error.message);
}
}
// Validation des formats de permission
try {
const hasAccess = service.checkPermission(permissions, 'invalid-format');
} catch (error) {
if (error instanceof InvalidPermissionFormatException) {
console.error('Format invalide:', error.message);
}
}
// Validation des composants manquants
try {
const hasAccess = service.checkPermission(permissions, 'users:');
} catch (error) {
if (error instanceof MissingPermissionComponentException) {
console.error('Composant manquant:', error.message);
}
}
// Validation des actions invalides
try {
const hasAccess = service.checkPermission(permissions, 'users:invalid');
} catch (error) {
if (error instanceof InvalidPermissionActionException) {
console.error('Action invalide:', error.message);
}
}
// Validation des permissions utilisateur
try {
const hasAccess = service.checkPermission(null, 'users:read');
} catch (error) {
if (error instanceof InvalidUserPermissionsException) {
console.error('Permissions invalides:', error.message);
}
}
// Gestion des permissions insuffisantes
try {
const hasAccess = service.checkPermission(permissions, 'admin:all');
if (!hasAccess) {
throw new InsufficientPermissionException('admin:all');
}
} catch (error) {
if (error instanceof InsufficientPermissionException) {
console.error('Accès refusé:', error.message);
}
}
// Validation des listes vides
try {
const hasAccess = service.checkMultiplePermissions(permissions, []);
} catch (error) {
if (error instanceof EmptyPermissionListException) {
console.error('Liste vide:', error.message);
}
}Exemple de gestion d'erreurs
import {
PermissionCheckerService,
InvalidPermissionFormatException,
InsufficientPermissionException,
InvalidUserPermissionsException,
UnsupportedHttpMethodException
} from '@un-dev-suisse/nestjs-permissions';
@Injectable()
export class MyController {
constructor(private readonly permissionService: PermissionCheckerService) {}
@Get()
async getData(@Req() request: Request) {
try {
const userPermissions = request.user?.permissions;
if (!userPermissions) {
throw new InvalidUserPermissionsException();
}
const hasAccess = this.permissionService.checkPermission(
userPermissions,
'data:read'
);
if (!hasAccess) {
throw new InsufficientPermissionException('data:read');
}
return { message: 'Accès autorisé' };
} catch (error) {
if (error instanceof InvalidUserPermissionsException) {
throw new BadRequestException('Permissions utilisateur invalides');
} else if (error instanceof InvalidPermissionFormatException) {
throw new BadRequestException('Format de permission invalide');
} else if (error instanceof InsufficientPermissionException) {
throw new ForbiddenException('Accès refusé');
}
throw error;
}
}
@Post()
async createData(@Req() request: Request, @Body() data: any) {
try {
const userPermissions = request.user?.permissions;
if (!userPermissions) {
throw new InvalidUserPermissionsException();
}
// Convertir la méthode HTTP en permission
const permissionType = this.permissionService.getPermissionFromMethod('POST');
const hasAccess = this.permissionService.checkPermission(
userPermissions,
`data:${permissionType}`
);
if (!hasAccess) {
throw new InsufficientPermissionException(`data:${permissionType}`);
}
return { message: 'Données créées' };
} catch (error) {
if (error instanceof UnsupportedHttpMethodException) {
throw new BadRequestException('Méthode HTTP non supportée');
} else if (error instanceof InvalidUserPermissionsException) {
throw new BadRequestException('Permissions utilisateur invalides');
} else if (error instanceof InsufficientPermissionException) {
throw new ForbiddenException('Accès refusé');
}
throw error;
}
}
}Format des permissions
Les permissions suivent le format : "ressource:action"
Actions supportées
create: Création de ressourcesread: Lecture de ressourcesupdate: Modification de ressourcesdelete: Suppression de ressourcesall: Toutes les actions
Exemples
"users:read": Permission de lecture des utilisateurs"posts:create": Permission de création d'articles"admin:all": Toutes les permissions d'administration
Masques de permissions
Le système utilise des masques binaires pour les permissions :
const PERMISSION_MASKS = {
CREATE: 0b1000, // 8
READ: 0b0100, // 4
UPDATE: 0b0010, // 2
DELETE: 0b0001, // 1
ALL: 0b1111, // 15
};Avantages de l'utilisation directe des exceptions
✅ Simplicité
- Code plus direct sans couche d'abstraction supplémentaire
- Pas besoin de mémoriser des méthodes statiques
⚡ Performance
- Pas d'appel de méthode statique supplémentaire
- Construction directe des exceptions
🎯 Flexibilité
- Possibilité de personnaliser les messages d'erreur si nécessaire
- Contrôle total sur la création des exceptions
📖 Lisibilité
- Plus facile de voir quelle exception est levée
- Code plus explicite et compréhensible
🛠️ Maintenabilité
- Moins de code à maintenir
- Pas de classe utilitaire à gérer
API
PermissionCheckerService
checkPermission(permissions: UserPermissions, permission: string): boolean
Vérifie si un utilisateur a une permission spécifique.
checkMultiplePermissions(permissions: UserPermissions, permissionList: string[]): boolean
Vérifie si un utilisateur a toutes les permissions d'une liste.
checkAnyPermission(permissions: UserPermissions, permissionList: string[]): boolean
Vérifie si un utilisateur a au moins une permission d'une liste.
getPermissionFromMethod(method: string): PermissionType
Convertit une méthode HTTP en type de permission.
Licence
MIT
