Гибкая система прав в CMS Bitrix: от простых проверок до собственных контроллеров

Раздел: Работа с CMS Bitrix -> Управление доступом в CMS

Управление доступом в Bitrix: обзор методов и примеров

В CMS Bitrix существует несколько подходов для проверки прав пользователей. Наиболее современным и гибким является использование пространства имён Bitrix\Main\Access. Ниже рассмотрены различные варианты, от простых проверок групп до создания собственных контроллеров доступа. Для каждого варианта указана цель, случаи использования, пример кода и типичные проблемы.

Как реализовать гибкую систему прав с помощью Bitrix\Main\Access?

Цель: создание масштабируемой системы разрешений на основе ролей и операций. Случаи использования: модули с кастомными сущностями, сложная иерархия прав, разделение доступа к элементам, разделам, админке.

Решение: использование классов Bitrix\Main\Access\AccessController и Bitrix\Main\Access\Permission\PermissionDictionary. Необходимо унаследовать AccessController, реализовать метод canDo, и зарегистрировать свои права через событие onBuildPermissionsList.


namespace MyModule\Access;

use Bitrix\Main\Access\AccessController;
use Bitrix\Main\Access\Permission\PermissionDictionary;
use Bitrix\Main\Access\User\AccessibleUser;

class ArticleAccessController extends AccessController
{
    protected function canDo(string $action, int $itemId = null, AccessibleUser $user = null): bool
    {
        if ($user === null) {
            $user = $this->user;
        }
        // Получаем права пользователя (роли) из базы
        $permissions = $this->getUserPermissions($user->getUserId());
        // Проверяем, есть ли нужное действие в правах
        return in_array($action, $permissions, true);
    }

    private function getUserPermissions(int $userId): array
    {
        // Логика получения прав для пользователя (из таблиц модуля)
        // Возвращает массив строк-действий, например ['edit_article', 'read_article']
        return ['read_article', 'edit_article'];
    }
}

Bitrix access php (управление доступом в bitrix php)

Далее в любом месте сайта можно проверить право:


use MyModule\Access\ArticleAccessController;

$accessController = new ArticleAccessController(\Bitrix\Main\Engine\CurrentUser::get());
if ($accessController->check('edit_article', $articleId)) {
    echo 'Разрешено';
} else {
    echo 'Запрещено';
}

Типичные ошибки: забыть зарегистрировать права через событие onBuildPermissionsList (для отображения в админке); неправильная работа с кешированием ролей – после изменения прав необходимо сбрасывать кеш пользователя (\Bitrix\Main\Data\Cache::clearCache(true, '/user_permissions/')); отсутствие проверки на $user (может быть null в консоли).

Как проверить, является ли пользователь администратором?

Цель: быстрая проверка глобальных прав. Случаи использования: защита одиночных кнопок, вызов служебных функций, отладка.

Вариант 1: использование метода $USER->IsAdmin().


global $USER;
if ($USER->IsAdmin()) {
    echo 'Администратор';
}

Вариант 2: проверка принадлежности к группе администраторов (ID=1).


global $USER;
$groups = $USER->GetUserGroupArray();
if (in_array(1, $groups)) {
    echo 'Администратор';
}

Типичные ошибки: вызов $USER->IsAdmin() в неподходящем контексте (например, до инициализации ядра) приводит к ошибке; полагаться только на проверку группы 1 (группа может быть переименована).

Как получить список групп пользователя и проверить произвольную?

Цель: проверка принадлежности к определённой группе (например, «Менеджеры», «Авторы»). Случаи использования: простые ролевые ограничения без необходимости строить сложные права.

Решение: получение массива групп через $USER->GetUserGroupArray() или CUser::GetUserGroup($userId).


global $USER;
$userGroups = $USER->GetUserGroupArray();
$managerGroupId = 7;
if (in_array($managerGroupId, $userGroups)) {
    echo 'Пользователь является менеджером';
}

Типичные ошибки: использование устаревшего CGroup::GetList() без фильтра; забыть учесть, что группы могут быть добавлены через включаемые группы (parent groups) – функция возвращает только прямые группы, для полной картины нужно использовать \Bitrix\Main\GroupTable::getList() с join на user_group.

Как проверить права на элемент инфоблока?

Цель: определить, может ли пользователь читать/редактировать/удалять конкретный элемент. Случаи использования: публичная часть, админка, custom компоненты.

Решение: использование метода CIBlockElement::checkAccess() или CIBlock::GetPermission().


$iblockId = 2;
$elementId = 15;
$userId = $USER->GetID();
$access = CIBlockElement::checkAccess($elementId, $iblockId, $userId, 'read');
if ($access) {
    echo 'Доступ к чтению есть';
}

Для проверки права на редактирование передаётся 'edit'. Метод CIBlock::GetPermission() возвращает уровень доступа (0-100).

Типичные ошибки: передача неверного ID инфоблока; попытка проверить доступ до инициализации инфоблоков; забыть, что права на элемент наследуются от раздела, а права раздела от инфоблока – нужно явно вызывать соответствующие методы проверки.

Как проверить доступ к модулю или странице админки?

Цель: ограничить доступ к определённым разделам административного интерфейса. Случаи использования: кастомные модули, настройки прав на страницы.

Решение: использование $APPLICATION->GetGroupRight($moduleId) или CMain::GetGroupRight().


$moduleId = 'my.module';
$groupRight = $APPLICATION->GetGroupRight($moduleId);
if ($groupRight >= 'R') {
    echo 'Пользователь имеет доступ на чтение к модулю';
}

Типичные ошибки: неверное имя модуля; отсутствие регистрации прав в файле options.php или в базе; путаница между буквенными правами ('D','R','W','X').

Выбор конкретного подхода зависит от сложности системы прав. Для единичных проверок достаточно $USER->IsAdmin() или проверки групп. Для гибких и расширяемых решений рекомендуется использовать Bitrix\Main\Access.

Расширенные примеры управления доступом

Пример 1: Создание полноценного AccessController с ролевой моделью

Создадим контроллер, который использует таблицу ролей. Предположим, есть таблица b_my_module_role_permission с полями: ROLE_ID, PERMISSION_ID (например, 'edit_article', 'delete_article'), а у пользователя есть связь с ролями через таблицу b_my_module_user_role.

Пример

namespace MyModule\Access;

use Bitrix\Main\Access\AccessController;
use Bitrix\Main\Access\User\AccessibleUser;

class RoleBasedAccessController extends AccessController
{
    protected function canDo(string $action, int $itemId = null, AccessibleUser $user = null): bool
    {
        if (!$user) {
            $user = $this->user;
        }
        $userId = $user->getUserId();
        if (!$userId) {
            return false;
        }
        // Получаем роли пользователя
        $roles = $this->getUserRoles($userId);
        foreach ($roles as $roleId) {
            // Проверяем, есть ли у роли нужное действие
            if ($this->roleHasPermission($roleId, $action)) {
                return true;
            }
        }
        return false;
    }

    private function getUserRoles(int $userId): array
    {
        $result = [];
        $dbRoles = \Bitrix\Main\Application::getConnection()->query(
            "SELECT ROLE_ID FROM b_my_module_user_role WHERE USER_ID = ".intval($userId)
        );
        while ($row = $dbRoles->fetch()) {
            $result[] = $row['ROLE_ID'];
        }
        return $result;
    }

    private function roleHasPermission(int $roleId, string $permissionId): bool
    {
        $row = \Bitrix\Main\Application::getConnection()->query(
            "SELECT 1 FROM b_my_module_role_permission WHERE ROLE_ID = ".$roleId." AND PERMISSION_ID = '".\Bitrix\Main\Application::getConnection()->getSqlHelper()->forSql($permissionId)."'"
        )->fetch();
        return $row !== false;
    }
}
Пример проверки:
$controller = new RoleBasedAccessController(\Bitrix\Main\Engine\CurrentUser::get());
var_dump($controller->check('edit_article', null)); // true, если право есть

Пример 2: Использование PermissionDictionary для описания прав

Права можно описать в виде конфигурации и зарегистрировать через событие onBuildPermissionsList.

Пример

use Bitrix\Main\Access\Permission\PermissionDictionary;

class ArticlePermission extends PermissionDictionary
{
    const EDIT_ARTICLE = 'edit_article';
    const DELETE_ARTICLE = 'delete_article';
    const READ_ARTICLE = 'read_article';

    public static function getPermissions(): array
    {
        return [
            self::EDIT_ARTICLE => [
                'title' => 'Редактирование статьи',
                'description' => 'Позволяет изменять содержание статьи',
            ],
            self::DELETE_ARTICLE => [
                'title' => 'Удаление статьи',
                'description' => 'Позволяет удалять статьи',
            ],
            self::READ_ARTICLE => [
                'title' => 'Чтение статьи',
                'description' => 'Просмотр текста статьи',
            ],
        ];
    }
}

Регистрация в обработчике:

Пример

\Bitrix\Main\EventManager::getInstance()->addEventHandler(
    'main',
    'OnBuildPermissionsList',
    function (\Bitrix\Main\Event $event) {
        return new \Bitrix\Main\EventResult(
            \Bitrix\Main\EventResult::SUCCESS,
            [
                'my_module' => [
                    'title' => 'Мой модуль',
                    'permissions' => ArticlePermission::getPermissions(),
                ]
            ]
        );
    }
);

Пример 3: Проверка прав с учётом владельца элемента

Часто нужно, чтобы пользователь мог редактировать только свои элементы. Модифицируем canDo:

Пример

protected function canDo(string $action, int $itemId = null, AccessibleUser $user = null): bool
{
    if (!$user) {
        $user = $this->user;
    }
    // Если действие 'edit_article', проверяем владельца
    if ($action === 'edit_article' && $itemId) {
        $ownerId = $this->getArticleOwner($itemId);
        if ($ownerId === $user->getUserId()) {
            return true;
        }
        // Если не владелец, смотрим, есть ли глобальное право
        return $this->hasGlobalPermission($user->getUserId(), 'edit_any_article');
    }
    return false;
}

Пример 4: Работа с правами на раздел инфоблока

Пример

$sectionId = 10;
$iblockId = 2;
$userId = $USER->GetID();
// Получить уровень доступа к разделу
$sectionPermission = CIBlockSection::checkAccess($sectionId, $iblockId, $userId, 'read');
if ($sectionPermission) {
    echo 'Раздел доступен для чтения';
}
Результат: true или false.

Пример 5: Кеширование прав в AccessController

Пример

use Bitrix\Main\Data\Cache;

protected function getUserPermissionsCache(int $userId): array
{
    $cache = Cache::createInstance();
    $cacheKey = 'user_'.$userId.'_permissions';
    $cachePath = '/user_permissions/';
    if ($cache->initCache(86400, $cacheKey, $cachePath)) {
        return $cache->getVars();
    }
    $permissions = $this->loadPermissionsFromDb($userId);
    $cache->startDataCache();
    $cache->endDataCache($permissions);
    return $permissions;
}

Эти примеры покрывают большинство сценариев управления доступом в Bitrix. Выбор конкретной реализации зависит от архитектуры модуля и требований к производительности.

Управление доступом в Bitrix PHP - comments

En
Bitrix access php (php)