php - Cómo diseñar un sistema de control de acceso basado en funciones jerárquicas
mysql permissions (1)
Hay una forma de implementar la herencia de roles mediante el uso de relaciones recursivas en Table Roles
, al hacer referencia de roles a otro registro:
Esta relación agregará 1 : n
herencia dentro del registro de Roles
. Puede obtener un árbol de jerarquía completo con esta función almacenada:
CREATE FUNCTION `getHierarchy`(`aRole` BIGINT UNSIGNED)
RETURNS VARCHAR(1024)
NOT DETERMINISTIC
READS SQL DATA
BEGIN
DECLARE `aResult` VARCHAR(1024) DEFAULT NULL;
DECLARE `aParent` BIGINT UNSIGNED;
SET `aParent` = (SELECT `parent` FROM `Roles` WHERE `id` = `aRole`);
WHILE NOT `aParent` IS NULL DO
SET `aResult` = CONCAT_WS('','', `aResult`, `aParent`);
SET `aParent` = (SELECT `parent` FROM `Roles` WHERE `id` = `aParent`);
END WHILE;
RETURN IFNULL(`aResult`, '''');
END
Entonces, puede obtener todos los permisos concedidos con algo como esto:
SELECT
`permission_id`
FROM
`Permission_Role`
WHERE
FIND_IN_SET(`role_id`, `getHierarchy`({$role}))
AND
grant;
Si no es suficiente, entonces puede hacer otra tabla para la herencia:
Pero, en este caso, necesitó otro algoritmo de obtención de jerarquía.
Para resolver el problema de anulación , deberá obtener permisos de función y de usuario. Luego, escriba permisos de user
sobre permisos de roles
para la session
.
Además, sugiero eliminar las columnas de grant
en Permission_Role
y Permission_User
. No es necesario mapear todos los permisos para cada uno de ellos. Solo lo suficiente para usar las consultas EXISTS
: si hay un registro, entonces se concede el permiso; de lo contrario, no es así. Si necesita recuperar todos los permisos y estados, puede usar LEFT JOIN
s.
El trato básico es que tenemos un "kickstart" personalizado para nuestros proyectos. Para esto, estamos buscando rehacer el control del usuario. Sé que hay muchas preguntas sobre RBAc general, pero no puedo encontrar ninguna en el rbac jerárquico.
Nuestros requisitos son:
- Los roles se pueden asignar a permisos de grupo
- Si la función no tiene una entrada de permiso, se denegará automáticamente.
- Un usuario puede recibir permisos de anulación
- Los usuarios que anulan los permisos son una concesión o una denegación
- Si a un usuario se le niega explícitamente un permiso, sin importar qué roles diga "concedido", prevalecerá la anulación.
- Los usuarios pueden tener múltiples roles
- Los roles pueden tener jerarquía
- Los roles pueden heredar de otros roles (por ejemplo, un rol de "Foro Súper Moderador" es un "Moderador del Foro" y un "Mantenimiento del Sistema", y el rol del "Moderador del Foro" ya hereda de la función "Usuario del Foro")
- Los roles que heredan de otro rol que deniega u otorga un privilegio anulan su permiso de hijo
- Los permisos se agrupan por "módulo" (por ejemplo, un módulo "Blog" puede tener un permiso "editar entrada" y un módulo "Foro" puede tener un permiso de "entrada de edición" y no chocarán)
- Hay un permiso "Todo y cualquier cosa" que otorga automáticamente acceso completo
Entonces, con esos requisitos fuera del camino, así es como estoy pensando en hacerlo.
Tabla: Usuarios
id | int | unique id
Tabla: Roles
id | int | unique id
--------------|---------------------------------------------
title | varchar | human readable name
Tabla: Permisos
id | int | unique id
--------------|---------------------------------------------
module | varchar | module name
--------------|---------------------------------------------
title | varchar | human readable name
--------------|---------------------------------------------
key | varchar | key name used in functions
Tabla: Role_User
role_id | int | id from roles table
--------------|---------------------------------------------
user_id | int | id from users table
Tabla: Permission_Role
id | int | unique id
--------------|---------------------------------------------
permission_id | int | id from permissions table
--------------|---------------------------------------------
role_id | int | id from roles table
--------------|---------------------------------------------
grant | tinyint | 0 = deny, 1 = grant
Tabla: Permiso_Usuario
id | int | unique id
--------------|---------------------------------------------
permission_id | int | id from permissions table
--------------|---------------------------------------------
user_id | int | id from users table
--------------|---------------------------------------------
grant | tinyint | 0 = deny, 1 = grant
Bueno, en realidad eso es la mitad, estoy seguro de esa parte, la parte en la que me estoy estancando es en los roles jerárquicos.
Entonces, ¿cómo diseño esto? Mi idea es que para guardar las consultas de la base de datos, voy a construir la matriz de permisos al iniciar sesión y guardarla en la sesión para que las consultas no tengan que ser demasiado simples, ya que solo se ejecutan una vez para cada inicio de sesión.
El problema que veo es que voy a necesitar conocer la jerarquía de los roles para poder resolver los permisos de roles heredados antes de resolver la herencia.
Los permisos de usuario son la parte fácil, los permisos por usuario son esencialmente el grupo finalmente resuelto.