El control de acceso basado en roles (RBAC) es un método para modificar el acceso y los privilegios en función de los roles de los usuarios individuales o de los grupos de usuarios de una organización.
El RBAC permite que los miembros de una organización tengan acceso, únicamente, a los recursos que necesitan para realizar su trabajo y restringe o impide los privilegios ilimitados a los recursos que no les corresponden.
RBAC vs ABAC
El control de acceso basado en roles y el control de acceso basado en atributos (ABAC) son dos tipos de métodos de control de acceso, pero sus enfoques son diferentes. Un caso de uso que requiere un sistema RBAC, sería si pretendemos conceder privilegios en la aplicación dependiendo de los roles de los usuarios.
Mientras que ABAC concede el acceso basado en una combinación de atributos, es decir, atributos de usuario, atributos de recursos, atributos asociados con el sistema o la aplicación a la que se accede, atributos del entorno, entre otros. Por ejemplo, los atributos del usuario pueden incluir información de biodatos, identificación única, rol, autorización de seguridad, y más.
Anécdota
En un proyecto reciente, a mi equipo se le encargó la implementación de un marco de control de acceso basado en roles para MongoDB (DB NoSQL), utilizando el esquema de mongoose ORM. En este marco de control de acceso vamos a considerar 3 entidades :
Contexto de implementación
- El Usuario tiene un Rol
- La Aplicación ha definido Recursos y,
- El rol tiene privilegios y permisos sobre los Recursos
Vamos a escribir algunos esquemas de mongoose para nuestras colecciones 😄
Esquema
recursos.modelos.js
/* RBAC - role-based access control
first create roles; role =[ "user", "guest", "organization", "superadmin" "globalsuperadmin"]
next, create resouuce, add their roles_id and permmissions
finally create users and indcate thier roles
*/
const mongooseClient = app.get('mongooseClient');
const { Schema } = mongooseClient;
const resources = new Schema({
name: { type: String, required: true },
slug: { type: String, required: true },
resources_roles: [{
roles_id: { type: Schema.Types.ObjectId, ref : 'Roles' },
roles_name: { type: String },
create: { type: Boolean },
delete: { type: Boolean },
update: { type: Boolean },
read: { type: Boolean },
}]
}, {
timestamps: true
});
return mongooseClient.model('resources', resources);
roles.models.js
const mongooseClient = app.get('mongooseClient');
const { Schema } = mongooseClient;
module.exports = function (app) {
const mongooseClient = app.get('mongooseClient');
const { Schema } = mongooseClient;
const roles = new Schema({
name: { type: String, required: true },
slug: { type: String, required: true },
}, {
timestamps: true
});
return mongooseClient.model('roles', roles);
};
users.models.js
const mongooseClient = app.get('mongooseClient');
const { Schema } = mongooseClient;
module.exports = function (app) {
const mongooseClient = app.get('mongooseClient');
const { Schema } = mongooseClient
const users = new mongooseClient.Schema({
email: {type: String, unique: true, lowercase: true},
password: { type: String },
first_name: { type: String },
last_name: { type: String },
roles: { type: Schema.Types.ObjectId, ref : 'Roles' },
}, {
timestamps: true
});
return mongooseClient.model('users', users);
};
Ahora, cuando quieras los permisos de un rol sobre un recurso, sólo tienes que buscar role_id
y resource_id
y comprobar qué permisos están establecidos como true
en el resources collection
.
Middleware de autorización
users.post('/', getAuth, someMethod)
Asumiendo que tienes un token de algún tipo en la petición que identifica al usuario que hace la publicación, y adjuntando la instancia del usuario al objeto de la petición puedes hacer esto:
// pseudo code
getAuth = function (req, res, next) {
if(req.user) {
// query to get the user role's permissions for a resource
if(token){
// handle jwt token authenticity and decrypt payload
// get permission handler
db.getPerms({ role_id: req.user.role_id, resource_id: req.resource.id})
.then((perms) => {
var allow = false;
// mapping of methods to permissions
perms.forEach(function(perm){
if (req.method == "POST" && perms.create) allow = true;
else if (req.method == "GET" && perms.read) allow = true;
else if (req.method == "PUT" && perms.write) allow = true;
else if (req.method == "DELETE" && perm.delete) allow = true;
})
if (allow) next();
else {
res.status(403).send({error: 'access denied'});
}
})
.catch((err)=> {
//handle your reject and catch here
})
} else{
res.status(400).send({error: 'invalid token'})
}
Este es un poco de Pseudo-código, mostrando cómo el middleware de autenticación puede ser escrito.😄
¡Este no es el framework más optimizado para implementar RBAC!
Gracias por la audiencia y espero que hayas encontrado este artículo útil.