Как создать иерархическую систему управления доступом на основе ролей
Основная сделка заключается в том, что у нас есть собственный "kickstart" для наших проектов. Для этого мы пересматриваем пользовательский элемент управления. Я знаю, что есть много вопросов об общем rbac, но я не могу найти ни одного иерархического rbac?
Наши требования:
- Роли могут быть назначены для групповых разрешений
- Если в роли нет записи разрешения, она автоматически отказывается
- Пользователю могут быть предоставлены переопределяющие разрешения
- Пользователи, переопределяющие разрешения, являются либо грантом, либо deny
- Если пользователю явно отказано в разрешении, независимо от того, какие роли говорят "предоставлено", выигрывает переопределение.
- Пользователи могут иметь несколько ролей
- Роли могут иметь иерархию
- Роли могут наследоваться от других ролей (например, роль "Модератор форума" "Модератор форума" - это "Модератор форума" и "Системный помощник", а роль "Модератор форума" уже наследуется от роли "Пользователь Форума" )/li >
- Роли, которые наследуются от другой роли, которая отказывает или предоставляет привилегию, переопределяет их дочернее разрешение.
- Разрешения сгруппированы по модулю (например, модуль "Блог" может иметь разрешение "редактировать запись", а модуль "Форум" может иметь разрешение "редактировать запись", и они не будут сталкиваться)
- Имеется разрешение "Все и все", которое автоматически предоставляет полный доступ
Итак, с учетом этих требований, вот как я думаю об этом.
Таблица: пользователи
id | int | unique id
Таблица: Роли
id | int | unique id
--------------|---------------------------------------------
title | varchar | human readable name
Таблица: Разрешения
id | int | unique id
--------------|---------------------------------------------
module | varchar | module name
--------------|---------------------------------------------
title | varchar | human readable name
--------------|---------------------------------------------
key | varchar | key name used in functions
Таблица: Role_User
role_id | int | id from roles table
--------------|---------------------------------------------
user_id | int | id from users table
Таблица: 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
Таблица: Permission_User
id | int | unique id
--------------|---------------------------------------------
permission_id | int | id from permissions table
--------------|---------------------------------------------
user_id | int | id from users table
--------------|---------------------------------------------
grant | tinyint | 0 = deny, 1 = grant
Ну, на самом деле эта половина, эта часть, о которой я уверен, часть, за которую я застреваю, - это иерархические роли.
Итак, как мне это создать?
Моя идея состоит в том, что для сохранения запросов к базе данных я просто собираюсь создать матрицу разрешений при входе в систему и сохранить ее на сеансе, чтобы запросы не были слишком простыми, поскольку они запускаются только один раз для каждого входа.
Проблема, которую я вижу, заключается в том, что мне нужно будет знать иерархию ролей, чтобы я мог разрешить права унаследованных ролей до того, как я разрешу наследование.
Разрешения пользователя - это легкая часть, разрешения для каждого пользователя по существу являются окончательно разрешенной группой.
Ответы
Ответ 1
Существует способ реализовать наследование роли с помощью рекурсивного отношения к таблице Roles
, сделав ссылку на другую запись:
![1:n inheritance]()
Это отношение добавит наследование 1 : n
в записи Roles
. Вы можете получить целое дерево иерархии с помощью этой хранимой функции:
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
Затем вы можете получить все предоставленные разрешения с чем-то вроде этого:
SELECT
`permission_id`
FROM
`Permission_Role`
WHERE
FIND_IN_SET(`role_id`, `getHierarchy`({$role}))
AND
grant;
Если этого недостаточно, вы можете сделать другую таблицу для наследования:
![n:m inheritance]()
Но в этом случае нужен еще один алгоритм получения иерархии.
Чтобы решить проблему переопределения, вам нужно будет получить разрешения на роль и разрешения пользователей. Затем напишите user
разрешения на Roles
разрешения на session
.
Кроме того, я предлагаю удалить столбцы grant
в Permission_Role
и Permission_User
. Нет необходимости отображать каждое разрешение для каждого из них. Достаточно просто использовать запросы EXISTS
: если есть запись, то разрешение предоставляется, иначе - нет. Если вам нужно получить все разрешения и статусы, вы можете использовать LEFT JOIN
s.