Права в своём модуле - уровни, проверка, интерфейс настроек
Делаем права у своего решения: объявление уровней доступа, их настройка группам, проверка уровня в коде и граница между правами модуля и правами на данные.
Механика
У каждого модуля платформы есть собственные права доступа для групп пользователей. Это отдельный слой, не связанный ни с правами на файлы, ни с правами на инфоблоки и заказы.
Уровень доступа - это буква, а не набор флажков. Модуль объявляет свой список уровней, а администратор назначает группам нужный уровень в настройках модуля.
Список уровней объявляет сам класс установки модуля. Он возвращает описание: какие буквы существуют и как они называются на понятном администратору языке.
Проверка уровня выполняется одной строкой в прикладном коде. Метод приложения возвращает уровень текущего пользователя по имени модуля, и дальше код сравнивает его с нужным.
Права модуля отвечают на вопрос «что человек может делать в решении», а не «какие записи он видит». Отбор записей по владельцу или по подразделению - это уже прикладная логика, и её пишут отдельно.
Администратор сайта обходит проверки уровней. Это удобно при разборе, но опасно при приёмке: проверять права нужно под учётной записью обычного сотрудника, а не под своей.
Уровни хранятся у групп, а пользователь состоит в нескольких группах сразу. Итоговый уровень - самый высокий из назначенных, и это регулярно удивляет при разборе жалоб на лишний доступ.
Свои права стоит объявлять сразу, а не «когда понадобится». Добавить их в готовое решение позже дороже: прикладной код уже написан без проверок, и расставлять их приходится по всему модулю.
Шаги
- Придумать уровни доступа решения: обычно чтение, работа и настройка.
- Объявить список уровней в классе установки модуля с понятными названиями.
- Назначить группам нужные уровни в настройках модуля после установки.
- Проверять уровень в коде перед каждой операцией, а не только в интерфейсе.
- Отдельно описать, какие записи видит сотрудник, и реализовать этот отбор кодом.
Код
Объявляем уровни доступа модуля:
class vendor_shop extends CModule{ public $MODULE_GROUP_RIGHTS = 'Y'; // у модуля есть свои права доступа
public static function GetModuleRightList(): array { return [ 'reference_id' => ['D', 'R', 'W'], 'reference' => ['[D] Доступ закрыт', '[R] Просмотр', '[W] Полный доступ'], ]; }}Список уровней виден администратору в настройках модуля. Названия пишут словами человека, а не буквами: «просмотр отчётов» понятнее, чем «уровень R», хотя в коде сравнивается именно буква.
Проверяем уровень в прикладном коде:
$level = $APPLICATION->GetGroupRight('vendor.shop'); // уровень текущего пользователяif ($level < 'R') { ShowError('Недостаточно прав'); return; // проверка стоит до любой работы с данными}// администратор сайта получает полный уровень независимо от настроек модуляПроверку ставят до работы, а не после. Показать список и потом сообщить об отсутствии прав - худший вариант: данные уже ушли в браузер, а сообщение только раздражает.
Разделяем чтение и запись:
$canWrite = $APPLICATION->GetGroupRight('vendor.shop') >= 'W';if (!$canWrite && $request->isPost()) { throw new \RuntimeException('нет прав на изменение'); // запись требует своего уровня}Право на запись проверяют отдельно от права на чтение. Иначе сотрудник со справочным доступом отправляет форму руками и меняет данные, которых ему видеть хватало, а править - нет.
Проверяем права на своей странице в админке:
require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_before.php';\Bitrix\Main\Loader::includeModule('vendor.shop');if ($APPLICATION->GetGroupRight('vendor.shop') === 'D') { $APPLICATION->AuthForm('Доступ закрыт'); // страница закрывается до вывода}Отбираем записи по прикладному правилу:
$filter = ['=ACTIVE' => 'Y'];if ($APPLICATION->GetGroupRight('vendor.shop') < 'W') { $filter['=MANAGER_ID'] = $USER->GetID(); // менеджер видит только свои записи}$rows = \Vendor\Shop\OrderTable::getList(['filter' => $filter])->fetchAll();Отбор своих записей - прикладная логика поверх уровня доступа. Уровень отвечает, можно ли открыть раздел вообще, а фильтр - какие строки в нём показывать конкретному сотруднику.
Печатаем права всех групп при разборе:
$res = \CGroup::GetList($by = 'ID', $order = 'ASC', ['ACTIVE' => 'Y']);while ($group = $res->Fetch()) { printf("%-30s уровень=%s\n", $group['NAME'], \CMain::GetGroupRight('vendor.shop', [$group['ID']])); // уровень одной группы}// так видно, кому какой доступ выдан, без обхода интерфейса настроекПечать уровней по группам экономит время на разборе жалоб. Интерфейс настроек показывает то же самое, но глазами по десятку групп это сверяется дольше и с ошибками.
Показываем интерфейс по правам:
if ($canWrite) { $tabControl->BeginNextFormTab(); // вкладка настроек видна не всем echo $saveButton->render(); // кнопку сохранения тоже прячем от читателей}// интерфейс прячут для удобства, а доступ закрывают проверкой в кодеСкрытая кнопка - это удобство, а не защита проекта. Адрес обработчика подбирается за минуту, поэтому проверка в коде обязательна даже там, где интерфейс её уже учитывает.
Полезно завести в модуле один класс с методами вроде «может смотреть» и «может менять». Тогда прикладной код читается словами предметной области, а сравнение уровней живёт в одном месте и правится за минуту.
Ограничения
Уровни доступа модуля глобальны для сайта. Разные права на разных сайтах многосайтовой копии этим механизмом не задаются, и такие сценарии решают прикладной логикой.
Буквы уровней сравниваются как строки, и порядок задаёте вы сами. Придумывать десяток уровней не стоит: три-четыре покрывают почти любое решение и остаются понятными администратору.
Права модуля не влияют на его же фоновые задания. Агент выполняется без пользователя, и проверка уровня внутри него просто не имеет смысла.
Механизм не заменяет прав на данные платформы. Инфоблоки, заказы и файлы имеют свои права, и модуль обязан их учитывать, а не подменять собственной проверкой.
Уровни доступа не документируют сами себя. Что именно означает каждый уровень в вашем решении, пишут в описании модуля и в инструкции для администратора, иначе через год этого не помнит и сам автор.
Проверки прав легко разъезжаются с интерфейсом при доработках. Новая страница или новое действие требуют своей проверки, и их полезно перечислять в одном месте кода, а не искать по всему модулю.
Типичные проблемы
В настройках модуля нет вкладки с правами.
Класс установки не объявил, что у модуля есть свои права доступа. Признак прав и список уровней описывают в самом классе модуля.
Сотрудник открывает страницу, которую видеть не должен.
Проверка уровня стоит только в меню, а не на самой странице. Каждую страницу закрывают проверкой до вывода содержимого.
Права проверяются, а данные всё равно чужие.
Уровень доступа перепутан с отбором записей по владельцу. Отбор пишут прикладным фильтром поверх уровня доступа.
У сотрудника прав больше, чем назначали.
Он состоит в нескольких группах, и берётся самый высокий уровень. Состав групп проверяют целиком, а не одну ожидаемую группу.
Под администратором всё работает, под менеджером нет.
Проверки писались и проверялись только под полным доступом. Приёмку ведут под учётной записью обычного сотрудника.
Частые вопросы
Сколько уровней доступа заводить?
Обычно хватает трёх: закрыто, просмотр, полный доступ. Больше уровней усложняют настройку и почти никогда не используются целиком.
Чем права модуля отличаются от прав на инфоблок?
Права модуля говорят, что человек может делать в вашем решении. Права на инфоблок и заказы - про конкретные данные платформы и живут отдельно.
Как проверить права в фоновом задании?
Никак: агент выполняется без пользователя и без его прав. Ограничения для фоновых операций описывают настройками решения, а не правами.
Можно ли выдать права одному сотруднику?
Права назначаются группам, поэтому под сотрудника заводят отдельную группу. Это заодно документирует, зачем такой доступ выдан.
Нужны ли права простому модулю без интерфейса?
Если у решения есть страницы в админке - да, обязательно. Модулю из одного обработчика события они не нужны.
Смежное
-
Права доступа на практике - оглавление подтемы
-
Права не применяются: разбор причин - разбор, когда доступ не тот
-
Роли менеджеров: что видит и что может в админке - права штатных модулей магазина
-
Права на инфоблок и заказы: выдача из интерфейса и кодом - права на сами данные
-
Свой модуль: структура, установка, автозагрузка - где живёт класс установки
-
Своя страница в админке: список, форма, пункт меню - что закрывают этой проверкой
-
Пользователи, группы и права - устройство прав целиком
-
Права доступа целиком: уровни, режимы, наследование, проверки - место прав модуля среди остальных систем