Volver a la página principal
viernes 20 septiembre 2024
27

Cómo utilizar CASL en Node.js

CASL (Code Access Security Layer) es una librería de autorización para JavaScript que te permite definir permisos y reglas de acceso en tus aplicaciones de forma sencilla. Se utiliza comúnmente en aplicaciones Node.js para controlar qué acciones pueden realizar los usuarios en diferentes recursos, lo que es esencial para construir sistemas con múltiples niveles de roles y permisos.

Instalación de CASL en Node.js

Para utilizar CASL en tu proyecto, primero debes instalarlo:

npm install @casl/ability

Configuración básica de CASL

CASL se basa en la creación de una habilidad (Ability), que define lo que un usuario puede o no hacer. Se define una habilidad con reglas que determinan las acciones permitidas para un recurso específico.

Aquí un ejemplo básico:

const { AbilityBuilder, Ability } = require('@casl/ability');

// Definir las habilidades de un usuario
function defineAbilitiesFor(role) {
  const { can, cannot, build } = new AbilityBuilder(Ability);

  if (role === 'admin') {
    can('manage', 'all'); // Un administrador puede gestionar todo
  } else {
    can('read', 'Post'); // Un usuario normal solo puede leer posts
    cannot('delete', 'Post'); // Pero no puede eliminarlos
  }

  return build();
}

// Crear habilidades para un usuario 'admin'
const ability = defineAbilitiesFor('admin');

// Verificar permisos
console.log(ability.can('delete', 'Post')); // true
console.log(ability.can('read', 'Post'));   // true

En este ejemplo, se definen las habilidades para dos roles: admin, que tiene acceso completo, y un usuario normal, que solo puede leer publicaciones pero no puede eliminarlas.

Algunos ejemplos

Aplicar CASL en rutas de Express

Para usar CASL en una aplicación Express y proteger rutas según los roles de los usuarios, se podría usar algo como lo siguiente:

const express = require('express');
const { AbilityBuilder, Ability } = require('@casl/ability');
const app = express();

// Definir habilidades según el rol
function defineAbilitiesFor(role) {
  const { can, build } = new AbilityBuilder(Ability);
  
  if (role === 'admin') {
    can('manage', 'all'); // Admin puede hacer todo
  } else {
    can('read', 'Post'); // Usuarios pueden leer posts
  }

  return build();
}

// Middleware de autorización
function checkAbility(action, subject) {
  return (req, res, next) => {
    const role = req.user.role; // Supongamos que el rol está en req.user
    const ability = defineAbilitiesFor(role);

    if (ability.can(action, subject)) {
      return next(); // Permitir acceso
    }

    return res.status(403).json({ message: 'Acceso denegado' });
  };
}

// Ruta protegida
app.get('/posts', checkAbility('read', 'Post'), (req, res) => {
  res.send('Lista de publicaciones');
});

app.listen(3000, () => {
  console.log('Servidor ejecutándose en http://localhost:3000');
});

Definir permisos condicionales

CASL también permite definir permisos basados en condiciones, como permitir que un usuario edite solo sus propios recursos:

const { AbilityBuilder, Ability } = require('@casl/ability');

function defineAbilitiesFor(user) {
  const { can, build } = new AbilityBuilder(Ability);

  if (user.role === 'admin') {
    can('manage', 'all');
  } else {
    can('read', 'Post');
    can('update', 'Post', { authorId: user.id }); // Puede actualizar solo sus posts
  }

  return build();
}

const ability = defineAbilitiesFor({ role: 'user', id: 1 });

console.log(ability.can('update', 'Post', { authorId: 1 })); // true
console.log(ability.can('update', 'Post', { authorId: 2 })); // false

En este ejemplo, el usuario solo puede actualizar publicaciones donde el authorId coincide con su propio id.

Verificación en el lado del frontend

CASL no solo se limita al backend. Puedes utilizar CASL también en el frontend para gestionar la visibilidad de botones o acciones basadas en los permisos del usuario:

import { Ability } from '@casl/ability';

const ability = new Ability([
  { action: 'read', subject: 'Post' },
  { action: 'delete', subject: 'Post', conditions: { authorId: 1 } }
]);

if (ability.can('delete', 'Post', { authorId: 1 })) {
  // Mostrar botón de eliminar
}

Documentación oficial

Para obtener más información y detalles avanzados sobre el uso de CASL, puedes consultar la documentación oficial de CASL.

Compartir:
Creado por:
Author photo

Jorge García

Fullstack developer