Descubra cómo combinar estas tecnologías con una demostración práctica.

El control de acceso basado en roles es un mecanismo de autenticación seguro. Puede usarlo para restringir el acceso a recursos específicos a usuarios que tienen ciertos roles.

Este tipo de autenticación ayuda a los administradores del sistema a controlar los permisos de acuerdo con las funciones designadas de los usuarios. Este nivel de control granular agrega una capa de seguridad, lo que permite que las aplicaciones eviten el acceso no autorizado.

Implementación del mecanismo de control de acceso basado en funciones mediante Passport.js y JWT

El control de acceso basado en roles (RBAC) es un mecanismo popular que se utiliza para imponer restricciones de acceso en las aplicaciones según los roles y permisos de los usuarios. Hay varios métodos disponibles para implementar el mecanismo RBAC.

Dos enfoques populares incluyen el uso de bibliotecas RBAC dedicadas como Control de acceso o aprovechar las bibliotecas de autenticación existentes para implementar el mecanismo.

instagram viewer

En este caso, los tokens web JSON (JWT) proporcionan una forma segura de transmitir credenciales de autenticación, mientras que Passport.js simplifica el proceso de autenticación al proporcionar una autenticación flexible software intermedio.

Con este enfoque, puede asignar roles a los usuarios y codificarlos en el JWT cuando se autentican. Luego puede usar el JWT para verificar la identidad y los roles del usuario en solicitudes posteriores, lo que permite la autorización basada en roles y el control de acceso.

Ambos enfoques tienen sus ventajas y pueden ser efectivos para implementar RBAC. La elección entre qué método implementar dependerá de los requisitos específicos de su proyecto.

Puedes descargar el código de este proyecto desde su repositorio GitHub.

Configurar un proyecto Express.js

Para empezar, configurar un proyecto Express.js localmente. Una vez que configure el proyecto, continúe e instale estos paquetes:

npm instalar cors dotenv mongoose cookie-parser jsonwebtoken mongodb \
pasaporte pasaporte-local

Próximo, crear una base de datos MongoDB o configurar un clúster en MongoDB Atlas. Copie el URI de conexión de la base de datos y agréguelo a un .env archivo en el directorio raíz de su proyecto de su proyecto:

CONNECTION_URI="URI de conexión"

Configurar la conexión de la base de datos

En el directorio raíz, cree un nuevo utils/db.js y agregue el código a continuación para establecer la conexión con el clúster de MongoDB que se ejecuta en Atlas usando Mongoose.

constante mangosta = requerir('mangosta');

constante conectarDB = asíncrono () => {
intentar {
esperar mangosta.conectar (proceso.env. CONEXIÓN_URI);
consola.registro("¡Conectado a MongoDB!");
} atrapar (error) {
consola.error("Error al conectarse a MongoDB:", error);
}
};

módulo.exportaciones = connectDB;

Definir el modelo de datos

En el directorio raíz, cree un nuevo modelo/usuario.modelo.js y agregue el siguiente código para definir un modelo de datos para los datos de los usuarios mediante Mongoose.

constante mangosta = requerir('mangosta');

constante esquema de usuario = nuevo mangosta. Esquema({
nombre de usuario: Cadena,
contraseña: Cadena,
role: Cadena
});

módulo.exportaciones = mangosta.modelo('Usuario', esquema de usuario);

Crear el controlador para los puntos finales de la API

Crear un nuevo controladores/usuario.controlador.js archivo en el directorio raíz y agregue el código a continuación.

Primero, haz estas importaciones:

constante Usuario = requerir('../modelos/usuario.modelo');
constante pasaporte = requerir('pasaporte');
constante { generar token } = requerir('../middleware/autorización');
requerir('../middleware/pasaporte')(pasaporte);

A continuación, defina la lógica para gestionar el registro de usuarios y la funcionalidad de inicio de sesión:

exportaciones.registerUser = asíncrono (requerido, res) => {
constante { nombre de usuario, contraseña, rol } = req.body;

intentar {
esperar User.create({ nombre de usuario, contraseña, rol });
res.status(201).json({ mensaje: 'Usuario registrado con éxito' });
} atrapar (error) {
consola.log (error);
res.status(500).json({ mensaje: '¡Ocurrió un error!' });
}
};

exportaciones.loginUser = (req, res, siguiente) => {
pasaporte.autenticar('local', { sesión: FALSO }, (err, usuario, información) => {
si (Error) {
consola.log (error);

devolver res.status(500).json({
mensaje: 'Ocurrió un error al iniciar sesión'
});
}

si (!usuario) {
devolver res.status(401).json({
mensaje: 'Credenciales de acceso invalidos'
});
}

req.login (usuario, { sesión: FALSO }, (error) => {
si (Error) {
consola.log (error);

devolver res.status(500).json({
mensaje: 'Ocurrió un error al iniciar sesión'
});
}

constante { _id, nombre de usuario, rol } = usuario;
constante carga útil = { ID de usuario: _id, nombre de usuario, rol };
constante token = generar token (carga útil);
res.cookie('simbólico', token, { solo http: verdadero });
devolver res.status(200).json({ mensaje: 'Inicio de sesión correcto' });
});
})(req, res, siguiente);
};

El registrarseUsuario La función maneja el registro de un nuevo usuario extrayendo el nombre de usuario, la contraseña y el rol del cuerpo de la solicitud. Luego crea una nueva entrada de usuario en la base de datos y responde con un mensaje de éxito o un error si ocurre alguno durante el proceso.

Por otro lado, el loginUser La función facilita el inicio de sesión del usuario utilizando la estrategia de autenticación local proporcionada por Passport.js. Autentica las credenciales del usuario y devuelve un token al iniciar sesión correctamente, que luego se almacena en una cookie para solicitudes autenticadas posteriores. Si se produce algún error durante el proceso de inicio de sesión, devolverá un mensaje apropiado.

Finalmente, agregue el código que implementa la lógica que obtiene todos los datos de los usuarios de la base de datos. Usaremos este extremo como la ruta restringida para garantizar que solo los usuarios autorizados con el rol de administración puede acceder a este punto final.

exportaciones.getUsers = asíncrono (requerido, res) => {
intentar {
constante usuarios = esperar Usuario.find({});
res.json (usuarios);
} atrapar (error) {
consola.log (error);
res.status(500).json({ mensaje: '¡Ocurrió un error!' });
}
};

Configurar una estrategia de autenticación local de Passport.js

Para autenticar a los usuarios después de que proporcionen sus credenciales de inicio de sesión, debe configurar una estrategia de autenticación local.

Crear un nuevo middleware/pasaporte.js archivo en el directorio raíz y agregue el siguiente código.

constante Estrategia local = requerir('pasaporte-local').Estrategia;
constante Usuario = requerir('../modelos/usuario.modelo');

módulo.exportaciones = (pasaporte) => {
pasaporte.use(
nuevo Estrategia local(asíncrono (nombre de usuario, contraseña, listo) => {
intentar {
constante usuario = esperar Usuario.findOne({nombre de usuario});

si (!usuario) {
devolver hecho(nulo, FALSO);
}

si (usuario.contraseña !== contraseña) {
devolver hecho(nulo, FALSO);
}

devolver hecho(nulo, usuario);
} atrapar (error) {
devolver hecho (error);
}
})
);
};

Este código define una estrategia de pasaporte.js local para autenticar a los usuarios en función del nombre de usuario y la contraseña proporcionados.

Primero, consulta la base de datos para encontrar un usuario con un nombre de usuario coincidente y luego procede a validar su contraseña. En consecuencia, devuelve el objeto de usuario autenticado si el proceso de inicio de sesión es exitoso.

Crear un middleware de verificación JWT

Dentro de software intermedio directorio, cree un nuevo archivo auth.js y agregue el siguiente código para definir un middleware que genere y verifique los JWT.

constante jwt = requerir('jsonwebtoken');
constante clavesecreta = proceso.env. LLAVE SECRETA;

constante generar token = (carga útil) => {
constante token = jwt.sign (carga útil, clave secreta, { expira en: '1h' });
devolver simbólico;
};

constante verificarToken = (rol requerido) =>(req, res, siguiente) => {
constante token = req.cookies.token;

si (!token) {
devolver res.status(401).json({ mensaje: 'No se proporcionó token' });
}

jwt.verify (token, secretKey, (err, decodificado) => {
si (Error) {
devolver res.status(401).json({ mensaje: 'Simbolo no valido' });
}

req.userId = decodificado.userId;

si (descodificado.role !== Rol requerido) {
devolver res.status(403).json({
mensaje: 'No tiene la autorización y los permisos para acceder a este recurso.'
});
}

próximo();
});
};

módulo.exportaciones = {generarToken, verificarToken};

El generar token La función crea un JWT con un tiempo de caducidad especificado, mientras que el verificarToken La función comprueba si el token está presente y es válido. Además, también verifica que el token decodificado contenga el rol requerido, esencialmente, asegurando que solo los usuarios con el rol y los permisos autorizados tengan acceso.

Para firmar de forma única los JWT, debe generar una clave secreta única y agregarla a su .env archivo como se muestra a continuación.

SECRET_KEY="Esta es una clave secreta de muestra."

Definir las rutas API

En el directorio raíz, cree una nueva carpeta y asígnele el nombre rutas. Dentro de esta carpeta, crea una nueva UserRoutes.jsy agregue el código siguiente.

constante expresar = requerir('expresar');
constante enrutador = expreso. enrutador();
constante controladores de usuario = requerir('../controladores/usuarioControlador');
constante { verificarToken } = requerir('../middleware/autorización');

enrutador.post('/api/registrar', controladores de usuario.registerUser);
enrutador.post('/api/iniciar sesión', UserControllers.loginUser);

enrutador.get('/api/usuarios', verificarToken('administración'), UserControllers.getUsers);

módulo.exportaciones = enrutador;

Este código define las rutas HTTP para una API REST. El usuarios ruta específicamente, servidores como la ruta protegida. Al limitar el acceso a los usuarios con el administración rol, aplica de manera efectiva el control de acceso basado en roles.

Actualizar el archivo del servidor principal

Abre tu servidor.js archivo y actualícelo de la siguiente manera:

constante expresar = requerir('expresar');
constante corazones = requerir('corazón');
constante analizador de cookies = requerir('analizador de cookies');
constante aplicación = expreso();
constante puerto = 5000;
requerir('dotenv').config();
constante conectarDB = requerir('./utils/db');
constante pasaporte = requerir('pasaporte');
requerir('./middleware/pasaporte')(pasaporte);

conectarDB();

aplicación.uso (express.json());
app.use (express.urlencoded({ extendido: verdadero }));
app.use (cors());
aplicación.uso (cookieParser());
app.use (pasaporte.inicializar());

constante rutas de usuario = requerir('./rutas/rutasusuario');
aplicación.uso('/', rutas de usuario);

app.listen (puerto, () => {
consola.registro(`El servidor se está ejecutando en el puerto ${puerto}`);
});

Finalmente, inicie el servidor de desarrollo para ejecutar la aplicación.

nodo servidor.js

Aproveche el mecanismo RBAC para mejorar sus sistemas de autenticación

La implementación del control de acceso basado en roles es una forma efectiva de mejorar la seguridad de sus aplicaciones.

Si bien la incorporación de bibliotecas de autenticación existentes para establecer un sistema RBAC eficiente es un gran enfoque, aprovechar las bibliotecas RBAC para Definir roles de usuario y asignar permisos explícitamente proporciona una solución aún más robusta, en última instancia, mejorando la seguridad general de su solicitud.