No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Control de roles

12/20
Recursos

Aportes 8

Preguntas 5

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Yo diria que es un 403, no tiene permisos de acceso. 401 yo lo uso solo para si es sesion o no.

Se debe trabajar en la gesti贸n de permisos y roles ya que no todos deben poder crear categor铆as o crear usuarios, 煤nicamente un usuario administrador podr铆a hacer eso.

Se crea un middleware que verifique que tipo de rol es, y lo que lo deje seguir o no.

En auth.handler.js se crea la funci贸n checkAdminRole la cual verificar谩 si el rol del usuario es admin o customer, si es admin entonces pasa al siguiente middleware, de lo contrario lanza un error unauthorized.

function checkAdminRole(req, res, next) {
  const user = req.user;
  if (user.role === 'admin') {
    next();
  } else {
    next(boom.unauthorized());
  }
}

A la ruta se le agrega el middleware, la l贸gica es:

  1. Autenticar, verificar el token y obtener los datos del user (*passport.authenticate)*.

  2. Verificar el tipo de rol de user (checkAdminRole).

  3. Validar los datos del body (validatorHandler).

  4. Conectarse al servicio.

router.post(
  '/',
  passport.authenticate('jwt', { session: false }),
  checkAdminRole,
  validatorHandler(createCategorySchema, 'body'),
  async (req, res, next) => {
    try {
      const body = req.body;
      const newCategory = await service.create(body);
      res.status(201).json(newCategory);
    } catch (error) {
      next(error);
    }
  }
);

Cuando se desea escalar y tener m谩s roles, la funci贸n checkAdminRole se vuelve poco mantenible, por ello creamos la funci贸n checkRoles que recibir谩 los roles que tendr谩n acceso a ese endpoint. Si en los roles se encuentra el rol del usuario, devolver谩 true y tendr谩 acceso al endpoint, de lo contrario devolver谩 false y arrojar谩 error unauthorized.

En resumen, la funci贸n checkRoles recibe un array de roles, verifica que user.role se encuentre en ese array, y si todo bien procede al siguiente middleware.

function checkRoles(...roles) {
  return (req, res, next) => {
    const user = req.user;
    if (roles.includes(user.role)) {
      next();
    } else {
      next(boom.unauthorized());
    }
  };
}

Haciendo la implementaci贸n del middleware en la ruta queda de la siguiente manera, agregando los roles a los que tendr谩 acceso ese endpoint.

router.post(
  '/',
  passport.authenticate('jwt', { session: false }),
  checkRoles('admin', 'seller'),
  validatorHandler(createCategorySchema, 'body'),
  async (req, res, next) => {
    try {
      const body = req.body;
      const newCategory = await service.create(body);
      res.status(201).json(newCategory);
    } catch (error) {
      next(error);
    }
  }
);

Se recomienda utilizar la librer铆a accesscontrol donde realmente y de forma explicita se gestionan permisos de una forma m谩s profunda y avanzada.

To create a role control, a middleware will be our best friend

First of all, let鈥檚 think about what we need, we need a middleware able to check what kind of users is authenticated, for this, let鈥檚 create a single function, which will receive a list of roles and return a middleware.

//@param roles array of roles that can access the route
function checkRole(roles) {

    return (req, res, next) => {
        const user = req.user;
        //Check if rol is allowed to access
        if (!roles.includes(user.role)) {
            next(boom.unauthorized("Unauthorized!You cannot do this, Admins have been notified "));
        } else {
            //If everything is right, go to next middleware
            next();
        }
    }
}

Finally just use it wherever you need to check role, por example:

router.post("/",
    passport.authenticate('jwt', { session: false }),
    checkRole(['admin', 'Captain']),
    validatorHandler(getOrderSchema, "body"),
    async(req, res, next) => {
        try {
            const body = req.body;
            res.status(201).json(await service.create(body));
        } catch (error) {
            next(error);
        }
    }
);

Recommendation

Acces Control NPM

Si estan usando insomia para hacer la pruebas de la API, pueden guardar el token del usuario al hacer login. Pega la siguiente linea, dentro del archivo de variables de entorno

{
	"TOKEN_ADMIN": "{% response 'body', 'req_1e7f7e044bd5407bbff202ad27392f6e', 'b64::JC50b2tlbg==::46b', no-history, 60 %}",
}

Nota: despu茅s de pegar la l铆nea de c贸digo aparecer谩 un recuadro en rojo, no se asusten, deben configurar los par谩metros seg煤n sus request disponible (esto se hace a traves de una ventana gr谩fica)

  • Function to Perform: deber ser response (origen de la info que se desea guardar)
  • Attribute: body ( que parte especifica del response contiene la info)
  • Request: [Auth] POST Login Admin, este el nombre de mi request
  • Filter: este es valor que deseamos guardar en la variable de entorno, en este caso es $.token
  • Trigger behavior: acci贸n a realizar una vez obtenida la info, en este caso No History, ya que solo queremos las info guardada en token

Haciendo que esto sea un poco m谩s escalable y mejores pr谩cticas:
Cre茅 un archivo index.js dentro de una carpeta 鈥榬oles鈥 y simplemente es esto:

const ROLES = {
  ADMIN: 'admin',
  USER: 'user',
  CUSTOMER: 'customer',
  SELLER: 'seller'
}

module.exports = ROLES

luego usamos esos valores en los archivos que querramos:

const ROLES = require('../roles/');

router.get('/',
  protectRoute,
  checkRoles(ROLES.ADMIN, ROLES.CUSTOMER, ROLES.SELLER),
  async (req, res, next) => {
  try {
    const categories = await service.find();
    res.json(categories);
  } catch (error) {
    next(error);
  }
});

No se si alguien ya lo puso antes, pero hice un peque帽o cambio al c贸digo para no poner un rol que de por si tendr谩 acceso a todo ( al menos en este caso) para no repetir 鈥渁dmin鈥 cada que se llama a la funci贸n hice lo siguiente:

function checkRoles(...roles){
    roles.push('admin');
    return (req, res, next) => {
        const user = req.user;
        if(roles.includes(user.role)){
        next()
        } else {
        next(boom.unauthorized());
        }
    }
}

馃懏鈥嶁檧 Clase #12: Control de roles 12/20 馃懏

Pasos: 馃摑

  • Vamos a implementar un control para el acceso de las peticiones, es decir, si se establece que seg煤n el tipo de role (鈥榓dmin鈥, 鈥榗ustomer鈥, 鈥榮eller鈥) tiene privilegios para acceder a las rutas como crear categor铆as, ver las categor铆as almacenadas, editar y eliminar categor铆as.

    Para ello, vamos a VSC, entramos a la carpeta middlewares, abrimos el archivo auth.handler.js, se implementan las funciones para chequear si el role del usuario que hizo el login tiene permitido hacer la petici贸n, las funciones checkAdminRole y checkRoles quedan:
//脡sta funci贸n solo eval煤a para el role 鈥榓dmin鈥
function checkAdminRole(req,res,next){
	console.log(req.user);
	//Se encuentra el payload
	const user=req.user;
	if(user.role==='admin'){
		next();
	}else{
		next(boom.unauthorized());
	}
}

//Los 3 puntos transorma todo argumento en array
function checkRoles(...roles){
	return(req,res,next)=>{
		const user=req.user;
		//Compara el role del usuario con los roles permitidos enviados
		if(roles.includes(user.role)){
			next();
		}else{
			next(boom.unauthorized());
		}
	}
}

module.exports={checkApiKey,checkAdminRole,checkRoles}


Guardamos, vamos a la carpeta routes y abrimos el archivo categories.router.js, se implementa la l贸gica en cada petici贸n, el c贸digo queda:

const express = require('express');
const passport = require('passport');

const CategoryService = require('./../services/category.service');
const validatorHandler = require('./../middlewares/validator.handler');
//Para veriicar si tiene autorizaci贸n:
const { checkRoles } = require('./../middlewares/auth.handler');
//const { checkAdminRole } = require('./../middlewares/auth.handler');
const { createCategorySchema, updateCategorySchema, getCategorySchema } = require('./../schemas/category.schema');

const router = express.Router();
const service = new CategoryService();

router.get('/',
	passport.authenticate('jwt', {session: false}),
	checkRoles('admin', 'seller', 'customer'),
	async (req, res, next) => {
		try {
			const categories = await service.find();
			res.json(categories);
		} catch (error) {
			next(error);
		}
});

router.get('/:id',
	passport.authenticate('jwt', {session: false}),
	checkRoles('admin', 'seller', 'customer'),
	validatorHandler(getCategorySchema, 'params'),
	async (req, res, next) => {
		try {
			const { id } = req.params;
			const category = await service.findOne(id);
			res.json(category);
		} catch (error) {
			next(error);
		}
	}
);

router.post('/',
	//Proteger este endpoint con passport
	passport.authenticate('jwt', {session: false}),
	//Verificar si est谩 autorizado con el role de 'admin'
	//checkAdminRole,
	checkRoles('admin'),
	validatorHandler(createCategorySchema, 'body'),
	async (req, res, next) => {
		try {
			const body = req.body;
			const newCategory = await service.create(body);
			res.status(201).json(newCategory);
		} catch (error) {
			next(error);
		}
	}
);

router.patch('/:id',
	passport.authenticate('jwt', {session: false}),
	checkRoles('admin', 'seller'),
	validatorHandler(getCategorySchema, 'params'),
	validatorHandler(updateCategorySchema, 'body'),
	async (req, res, next) => {
		try {
			const { id } = req.params;
			const body = req.body;
			const category = await service.update(id, body);
			res.json(category);
		} catch (error) {
			next(error);
		}
	}
);

router.delete('/:id',
	passport.authenticate('jwt', {session: false}),
	checkRoles('admin', 'seller'),
	validatorHandler(getCategorySchema, 'params'),
	async (req, res, next) => {
		try {
			const { id } = req.params;
			await service.delete(id);
			res.status(201).json({id});
		} catch (error) {
			next(error);
		}
	}
);

module.exports = router;


Guardamos, si no se ha compilado con: npm run dev en la terminal, esperar a Mi port 3000

  • Vamos a Insomnia, entramos a la carpeta Auth, duplicamos el Login y lo editamos y colocamos en uno: Login Admin y Login Customer.
  • Consultamos en la petici贸n POST de la carpeta Customer el 煤ltimo cliente creado, y con los datos hacemos un nuevo Login en Auth, el body en mi caso:
{
	"email": "[email protected]",
	"password": "23 23 23"
}


En la salida se obtiene el c贸digo 200 OK:

{
	"user": {
		"id": 4,
		"email": "[email protected]",
		"role": "customer",
		"createdAt": "2023-03-28T21:32:16.237Z"
	},
	"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOjQsInJvbGUiOiJjdXN0b21lciIsImlhdCI6MTY4MDAzOTE4M30.d49BvWGrgGtVcYHQEKTHS7CJeruE4mjTealUYgSwwS8"
}


Con ese token lo guardamos en Manage Environment, vamos ala carpeta Categories, luego a Get Categories, en la pesta帽a Auth, se selecciona Bearer y en TOKEN se coloca el token generado recientemente, al dar a Send, debe aparecer el c贸digo 200 OK con la lista de las Categor铆as almacenadas, en caso de que el cliente no tenga el role con privilegio, sale el c贸digo 401 Unauthorized.

Ni idea del por qu茅 postman se cada cargando eternamente a pesar de que el servidor resuelva que es un 403 u.u