Как создать иерархическую систему управления доступом на основе ролей

Основная задача заключается в том, что у нас есть собственный «кикстарт» для наших проектов. Для этого мы пересматриваем пользовательский элемент управления. Я знаю, что есть много вопросов об общем rbac, но я не могу найти ни одного иерархического rbac?

Наши требования:

  • Роли могут быть назначены для групповых разрешений
  • Если в роли нет записи разрешения, она автоматически отказывается
  • Пользователю могут быть предоставлены переопределяющие разрешения
  • Пользователи, переопределяющие права доступа, являются либо грантом, либо запрещают
  • Если пользователю явно отказано в разрешении, независимо от того, какие роли говорят «предоставлено», переопределение выигрывает.
  • Пользователи могут иметь несколько ролей
  • Роли могут иметь иерархию
  • Роли могут наследоваться от других ролей (например, роль «Супермодератор форума» – это «Модератор форума», а «Системный помощник», а роль «Модератор форума» уже наследуется от роли «Пользователь Форума»)
  • Роли, которые наследуются от другой роли, которая отказывает или предоставляет привилегию, переопределяет их разрешение для детей
  • Разрешения сгруппированы по модулю (например, модуль «Блог» может иметь разрешение «редактировать запись», а модуль «Форум» может иметь разрешение «редактировать запись», и они не будут сталкиваться)
  • Существует разрешение «Все и все», которое автоматически предоставляет полный доступ

Итак, с учетом этих требований, вот как я думаю об этом.

Таблица: Пользователи

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 

Ну, на самом деле это половина этого, эта часть, о которой я уверен, часть, которую я застрял, – это иерархические роли.

Итак, как мне это создать? Моя идея состоит в том, что для сохранения запросов к базе данных я просто собираюсь создать матрицу разрешений при входе в систему и сохранить ее на сеансе, чтобы запросы не были слишком простыми, поскольку они выполняются только один раз для каждого входа.

Проблема, которую я вижу, заключается в том, что мне нужно будет знать иерархию ролей, чтобы разрешить разрешения унаследованных ролей до того, как я разрешу наследование.

Разрешения пользователя – это легкая часть, разрешения для каждого пользователя – это, по сути, окончательно разрешенная группа.

Существует способ реализовать наследование роли с помощью рекурсивного отношения к Roles таблицы, сделав ссылку на другую запись:

1: n наследование

Это отношение добавит наследование 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 наследование

Но в этом случае нужен еще один алгоритм получения иерархии.


Чтобы устранить проблему с переопределением, вам нужно будет получить разрешения на роль и разрешения пользователей. Затем укажите права доступа user разрешениям на roles в session .


Кроме того, я предлагаю удалить столбцы grant в Permission_Role и Permission_User . Нет необходимости отображать каждое разрешение для каждого из них. Достаточно просто использовать EXISTS запросы: если есть запись, то разрешение предоставляется, иначе – это не так. Если вам нужно получить все разрешения и статусы, вы можете использовать LEFT JOIN s.