
Вы только что добавили новую кнопку в интерфейс. Заказчик просит: "Сделайте, чтобы только начальники смены её видели". Вы находите соответствующую группу в Bitrix и пишете проверку inGroup('НачальникСмены'). Кажется, задача решена.
Но через месяц появляются "Старшие мастера", которым тоже нужен этот доступ. Вы дописываете ||. Потом добавляется очередное условие. И еще, и еще, и еще... В итоге простая кнопка обрастает десятком строк логики, которая дублируется в разных компонентах.
Знакомая картина? Мы сталкивались с этим в каждом крупном проекте. Штатная система прав Bitrix отлично работает для коробочных модулей, но бессильна перед уникальной бизнес-логикой. Проверки групп "просачиваются" в код, делая его хрупким и непрозрачным.
Меня зовут Александр Костиков, я ведущий разработчик в НЛМК ИТ. В этой статье я покажу, как мы перестали "цементировать" бизнес-термины в коде и используем систему, где права меняются без правок в компонентах.
Если вы устали от проверок inGroup('СуперАдминистратор') - этот материал для вас.
Проблема: почему штатные права Bitrix не спасают
В Bitrix есть несколько систем прав, но все они изолированы:
Группы - для общих доступов к разделам.
Матрицы прав инфоблоков - своя логика.
Роли в CRM - своя вселенная.
ACL страниц - отдельная история.
Для кастомного функционала (ваши гриды, API-методы, кнопки) остаётся проверять принадлежность к группам в коде. Это ведёт к трём проблемам:
Цена изменений. Чтобы дать доступ новой группе, нужно найти и обновить все компоненты, где используется это правило. Пропустите один - получите несогласованное поведение.
Чёрный ящик. Нет единого места, где видно, "кто что может". Понимание системы прав требует чтения исходного кода.
Дублирование. Одно и то же правило копируется, а со временем его версии в разных файлах могут разойтись.
Мы хотели перейти от модели "правила в коде" к модели "правила в конфигурации", где сама проверка (canDoThis) остаётся в коде, а состав исполнителей (какие роли имеют это право) управляется централизованно.
Наш переломный момент настал в проекте с 40+ кастомными компонентами и самописными модулями. Каждый новый запрос на изменение прав вызывал тихий ужас у разработчиков. Мы поняли: нужно решение, которое отделит бизнес-логику прав от кода приложения.
Решение: Permission-First - права как инструменты
Мы взяли за основу простую метафору: права - это инструменты, роли - наборы инструментов.
Вместо проверки "ты Супервайзер?" код теперь спрашивает: "у тебя есть инструмент 'news.delete'?".
Если завтра Менеджеру понадобится удалять новости - мы просто добавим ему этот "инструмент" в набор, не меняя ни кода, ни его должности.
Архитектура в трёх китах:
Permission (Разрешение) - атомарное действие (
news.delete,report.export).Role (Роль) - именованный набор разрешений, привязанный к группе Bitrix.
Маппинг - таблица связей "Роль → Permissions".
Стандартные группы Bitrix остаются для назначения пользователям, но их бизнес-смысл теперь описывается через permissions.
Как это работает
Определение интерфейсов
interface Permission { public function getCode(): string; public function getName(): string; public function getDescription(): string; public function getCategory(): Category; } interface Role { public function getCode(): string; public function getName(): string; public function getDescription(): string; public function getCategory(): Category; public function isAssignable(): bool; public function isVisible(): bool; } interface Category { public function getCode(): string; public function getName(): string; public function getDescription(): string; }
Permission - атомарное действие.
Role - связь с системной группой.
Category - для группировки ролей и прав по смыслу (удобно для UI и аудита).
Работа со связями
Связи между ролями и правами, а также пользователями и ролями, реализуются через ORM-таблицы или кастомные сервисы. В Bitrix удобно назначать роли пользователям через группы (STRING_ID = код роли).
Реализация сценария
Описываем права и роли через классы/enum:
enum ExamplePermission: string implements Permission { case PAGE_VIEW = 'custom.page.view'; case EXPORT_DATA = 'grid.export'; } enum ExampleRole: string implements Role { case MANAGER = 'manager'; case AUDITOR = 'auditor'; }
Связываем роли и права (многие-ко-многим):
$rolePermissionRepo->createRelation(ExampleRole::MANAGER, ExamplePermission::EXPORT_DATA); $rolePermissionRepo->createRelation(ExampleRole::MANAGER, ExamplePermission::PAGE_VIEW); $rolePermissionRepo->createRelation(ExampleRole::AUDITOR, ExamplePermission::PAGE_VIEW);
Назначаем роли пользователям (например, через Bitrix-группы):
$userRoleRepo->grantRole($userId, ExampleRole::MANAGER);
Проверяем право:
$context = $contextService->get($userId); // или внутри контекста получать для текущего юзера сразу $contextService->current(); if (!$context->can(ExamplePermission::PAGE_VIEW)) { // блокируем исполнение }
Расширяемость через события Bitrix
Для поддержки модульности и масштабирования можно собирать права и роли через события:
class OnCollectPermissionsListener { public static function handle(): \Bitrix\Main\EventResult { return new \Bitrix\Main\EventResult( \Bitrix\Main\EventResult::SUCCESS, ['permissions' => ExamplePermission::cases()] ); } } $eventManager = \Bitrix\Main\EventManager::getInstance(); $eventManager->addEventHandler('role', 'OnCollectPermissions', [OnCollectPermissionsListener::class, 'handle']);
Аналогичным образом добавляются обработчики для сбора ролей. Это позволяет любому модулю/сервису в вашем проекте объявить свои права и роли.
Затем в репозиториях Ролей и Прав собираем весь список зарегистрированных сущностей:
$event = new \Bitrix\Main\Event('role', 'OnCollectPermissions'); $event->send(); $permissions = []; foreach ($event->getResults() as $eventResult) { if ($eventResult->getType() === \Bitrix\Main\EventResult::SUCCESS) { $list = $eventResult->getParameters()['permissions'] ?? []; foreach ($list as $permission) { $permissions[$permission->getCode()] = $permission; } } }
В нашем случае вся функциональность собрана в небольшой модуль.
Наша реализация - один из вариантов подхода Permission-Based Access Control (PBAC), который зарекомендовал себя в современных веб-фреймворках, тот же Битрикс использует подобную модель в модуле CRM храня все данные в таблицах.
Для разработчиков доступны решения такие как spatie/laravel-permission и подобные, мы взяли общую идею и реализовали под нужды наших проектов.
Преимущества подхода
Гибкость: любое действие контролируется отдельным permission, исходя из бизнес-логики.
Прозрачность и аудит: перечень прав ясен, архитектуру легко ревьюировать, можно строить отчёты по доступу.
Масштабируемость: легко добавлять новые сценарии без изменений существующей структуры.
Единый код проверки: все кастомные проверки делаются через один фасад.
Что учитывать
Требуется поддерживать уникальность кодов и синхронизацию с Bitrix-группами.
Необходимо поддерживать дополнительную логику миграций для создания связей и настройки прав между окружениями.
Дополнительная дисциплина и контроль - чтобы модель не разрослась и не вступила в конфликт с существующими ролями платформы.
Итог: Order from Chaos
Permission-first подход не заменяет Bitrix ACL, а дополняет его там, где платформа не предоставляет удобных инструментов. Мы получили:
Для разработчиков: Чистый код без бизнес-терминов.
Для бизнеса: Возможность менять правила доступа без программистов.
Для админов: Прозрачную систему, где видно, какая роль что может.
Система прав перестала быть "зашитой в коде" и стала управляемым бизнес-инструментом.
Это рабочий способ построить контролируемый, тестируемый и безопасный слой на уровне всего корпоративного решения.