RBAC
Controle de acesso baseado em roles com CASL.
Visao geral
O sistema de RBAC (Role-Based Access Control) usa a biblioteca CASL para definir permissoes granulares por role. O PlazerCLI gera 3 roles padrao e toda a infraestrutura de guards e abilities.
Roles padrao
| Role | Valor | Permissoes |
|---|---|---|
| Admin | admin |
Gerencia tudo (manage all). Acesso total ao sistema. |
| User | user |
Gerencia proprio perfil. Cria/edita/deleta seus proprios recursos. Leitura da organizacao. |
| Owner | owner |
Gerencia a organizacao e todos os recursos dentro dela. Nao pode deletar outros owners/admins. |
export enum Role {
ADMIN = 'admin',
USER = 'user',
OWNER = 'owner',
}
CASL Abilities
A AbilitiesFactory (NestJS) ou defineAbilitiesFor() (Express/Fastify) centraliza toda a logica de permissoes:
// Exemplo de abilities para o role OWNER
case Role.OWNER:
can('manage', 'Organization', { id: user.organizationId });
can('read', 'Organization');
can('manage', 'Post', { organizationId: user.organizationId });
can('manage', 'User', { organizationId: user.organizationId });
cannot('delete', 'User', { role: { in: [Role.ADMIN, Role.OWNER] } });
can('manage', 'User', { id: user.id });
break;
// Exemplo para USER
case Role.USER:
can('read', 'Organization', { id: user.organizationId });
can('read', 'User', { id: user.id });
can('update', 'User', { id: user.id });
can('create', 'Post');
can('read', 'Post', { organizationId: user.organizationId });
can('update', 'Post', { authorId: user.id });
can('delete', 'Post', { authorId: user.id });
break;
Se Prisma estiver habilitado, o CASL usa @casl/prisma para queries type-safe. Caso contrario, usa @casl/ability com MongoDB-style.
Guards por framework
NestJS — RolesGuard global + decorators
// O guard e registrado globalmente via APP_GUARD
@Global()
@Module({
providers: [
AbilitiesFactory,
{ provide: APP_GUARD, useClass: RolesGuard },
],
})
export class RbacModule {}
// Uso em controllers:
@Post('admin-only')
@Roles(Role.ADMIN)
createAdminResource() { ... }
@Delete(':id')
@Roles(Role.ADMIN, Role.OWNER)
deleteResource() { ... }
Express — Middleware requireRole()
import { requireRole } from './rbac/rbac.middleware.js';
import { Role } from './rbac/roles.js';
router.delete('/users/:id', requireRole(Role.ADMIN, Role.OWNER), handler);
router.post('/admin-only', requireRole(Role.ADMIN), handler);
Fastify — preHandler hook requireRole()
import { requireRole } from './rbac/rbac.hook.js';
import { Role } from './rbac/roles.js';
app.delete('/users/:id', {
preHandler: [authHook, requireRole(Role.ADMIN, Role.OWNER)]
}, handler);
Arquivos gerados
apps/api/src/rbac/
├── roles.enum.ts / roles.ts # Enum Role (ADMIN, USER, OWNER)
├── roles.decorator.ts # @Roles() decorator (NestJS)
├── roles.guard.ts # Guard global (NestJS)
├── rbac.middleware.ts # requireRole() (Express)
├── rbac.hook.ts # requireRole() (Fastify)
├── abilities.factory.ts # AbilitiesFactory (NestJS)
├── abilities.ts # defineAbilitiesFor() (Express/Fastify)
└── rbac.module.ts # Modulo global (NestJS)