«Дьявольский» ACL — мой вариант проверки прав

«Дьявольский» ACL — мой вариант проверки прав

Делаю свою CMS (точнее то, что я называю CMS). Проект дошел до уровня проверки прав пользователей. Такая система должна позволять:

  1. Проверять права пользователя на ресурс
  2. Назначать права на ресурс группе
  3. Наследование прав дочерней группе от родительской
  4. Правила на родительский ресурс распространяются на все дочерние ресурсы
  5. Наследование прав (пример: право на изменение включает в себя право на чтение)
Разрешения

Сначала немного терминологии, которой я буду придерживаться. Разрешение — это конкретное действие. Право — это возможность пользователя совершать какое либо действие. По умолчанию система имеет следующие предопределенный список разрешений. Имя Описание none Нет прав read Чтение create Создание update Изменение delete Удаление all Все права Разрешения в списке представлены от наименьшего к наибольшему ( т.е. каждое следующее разрешение (строка) включает в себя все предыдущие разрешения). К примеру если пользователю назначили право на Создание (create), то значит у него есть и право на чтение (read). Соответственно разрешение all — даёт все права. А разрешение none — это запрет всех прав.

Ресурсы

Ресурс задаётся в виде ссылки /aaa/bbb/ccc/. При этом все права, заданные, к примеру, для /aaa/, относятся и ко всем дочерним ресурсам: /aaa/bbb/, /aaa/bbb/ccc/ и т.д. Для ресурса /aaa/bbb/ ресурс /aaa/ — родительский, ресурс /aaa/bbb/ccc/ — дочерний.

Группы

Группа — это объект, в котором происходит назначение прав (задание правил) на ресурсы. Есть ОДНА родительская для всех групп группа. Эта группа имеет все права на все ресурсы. Обычно такую группу называют superadmin, god(бог). Но чтобы было отличие от других ACL — я назвал такую корневую группу diablo (дьявол). Так что в моей системе все права будут «от дьявола». Отсюда и название статьи про дьявольский acl . Каждая дочерняя группа может только УМЕНЬШАТЬ права. Т.е. если группа admin(администратор) имеет право create (создание) для ресурса /aaa/bbb/ccc/, то группа user (пользователь) не может получить право на удаление ресурса aaa/bbb/ccc/ — в этом случае произойдет увеличение права, так как разрешение delete (удаление) стоит выше разрешения create (создание). Также группа user(пользователь) не может получить право delete (удаление) на ресурсы /aaa/bbb/, /aaa/, / так как это родительские ресурсы для ресурса /aaa/bbb/ccc/ а значит в этом случае тоже произойдет увеличение прав. Принцип уменьшения прав нужен для того, чтобы можно было давать пользователям вести группы и при этом не опасаться, что они смогут получить доступ к ресурсам, которые вы не хотите им показывать, так как они не смогут добавить себе права, которых у них нет. Каждая группа может содержать только одно правило для одного ресурса (включая родительские ресурсы). К примеру если в группе установлено правило для ресурса /aaa/bbb/ccc/, то не должно быть других правил для ресурсов /aaa/bbb/ccc/, /aaa/bbb/, /aaa/, /

Таблицы

Таблицы для хранения данных.

Функция проверки: имеет ли пользователь разрешение на ресурс

В качестве примера будем проверять разрешение create пользователя на ресурс /aaa/bbb/ccc/index.html Сначала картинка дерева групп, на которой буду описывать примеры для лучшего понимания алгоритма (и мне самому в том числе). Группа №1 — это группа diablo (Дьявол), которая имеет все права на все. В группах 12, 13, 15, 10 заданы правила для нужного нам ресурса для разрешений, которые < заданного — что приводит к запрету на ресурс. В группах 3, 4, 22 заданы правила для нужного нами ресурса для разрешений, которые ≥ заданному — что снижает уровень доступа, но все-равно попадает под наш пример. Т.е. если в группе 1 на ресурс задано разрешение all, то в группе (к примеру) 3 задано разрешение delete, которое все-таки выше заданного в примере разрешения create.

    По таблице Users по идентификатору пользователя (и по идентификатору = 0 — идентификатор гостя) определяем список групп (aGroupsUsers), к которым относится данный пользователь. Для нашего примера это будет список следующих групп.

  • 23, 12, 6, 2, 1
  • 13, 6, 2, 1
  • 2, 1
  • 38, 27, 17, 8, 3, 1
  • 18, ,9, 4, 1
  • 20, 10, 4, 1
  • 32, 22, 11, 5, 1

Как можно заметить (если вы прочитали алгоритм работы) у нас получается достаточно много выборок из БД, так как при проверки ветки группы мы последовательно перемещаемся от дочерней группы к родительской и чем длиннее ветка, тем больше выборок из БД нужно делать. Один из вариантов увеличить скорость работы — это кешировать результаты поиска по группе. Т.е. если мы при очередной проверке определили что группа G имеет разрешение P для ресурса R, то мы можем сохранить это в отдельной таблице

В этом случае после шага 3 мы можем выбирать по списку групп aGroupsUsers и списку ресурсов aResources данные из таблицы Cache. Если в выбранных данных есть разрешения ≥ требуемого, то значит пользователь имеет доступ к ресурсу. Если нет — то выполняем проверки по описанному алгоритму. При проверке ветки групп учитываем информацию о запрете, выбранную из КЕШ-а. Я не буду описывать этот процесс подробно, так как это уже относится к конкретной реализации, а я в статье хотел сделать именно общее описание алгоритма работы. Но если у вас есть идеи оптимизации, то пишите их в комментариях.

📎📎📎📎📎📎📎📎📎📎