Как программно проверить права доступа пользователя к документу с учетом RLS в 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки прикладных решений на платформе 1С:Предприятие часто возникает задача определить, имеет ли текущий пользователь право на просмотр или изменение конкретного документа или элемента справочника. Ситуация усложняется, когда в информационной базе включено ограничение прав на уровне записей — RLS (Record Level Security).

Стандартные функции платформы не всегда дают нужный результат для конкретной строки или ссылки, поэтому разберем подробно все доступные способы проверки ограничений RLS — от пакетной обработки в запросах до использования готовых механизмов Библиотеки Стандартных Подсистем (БСП).

Почему стандартные функции платформы не подходят для RLS?

Проанализируем две распространенные встроенные функции и выясним, почему они не решают задачу проверки RLS для конкретного объекта:

  1. Функция ПравоДоступа() — проверяет только статические права метаданных, заданные в назначенных пользователю ролях (например, флаг «Чтение» или «Изменение» у документа РеализацияТоваровУслуг). Если у пользователя есть роль с правом чтения, но RLS запрещает доступ к конкретной организации, функция ПравоДоступа() все равно вернет Истина.
  2. Функция ПараметрыДоступа() — возвращает структуру параметров и условий ограничений, но не вычисляет итоговый булев результат для конкретной ссылки в базе данных.

Таким образом, для проверки доступа к конкретным экземплярам данных необходимо использовать либо язык запросов платформы, либо специализированные подсистемы БСП.

Решение 1: Пакетная проверка массива документов через запрос с временными таблицами

Разберем наиболее производительный и универсальный способ для ситуаций, когда необходимо получить полный список документов (например, по всем организациям) и проставить отметку доступности для текущего пользователя.

Алгоритм решения строится на следующих шагах:

  1. Включаем привилегированный режим и получаем полный список документов во временную таблицу.
  2. Отключаем привилегированный режим и выбираем только те документы, к которым у пользователя есть реальный доступ, используя конструкцию ВЫБРАТЬ РАЗРЕШЕННЫЕ.
  3. Выполняем ЛЕВОЕ СОЕДИНЕНИЕ полной таблицы с таблицей разрешенных документов и проверяем поле на NULL.

Посмотрим на пример реализации данного запроса в коде модуля:


Функция ПолучитьТаблицуДокументовСОтметкойДоступа(ПериодНачала, ПериодОкончания) Экспорт

    Запрос = Новый Запрос;
    
    // 1. Формируем текст пакетного запроса
    Запрос.Текст = 
    "ВЫБРАТЬ
    |    Реализация.Ссылка КАК Ссылка,
    |    Реализация.Организация КАК Организация,
    |    Реализация.Номер КАК Номер,
    |    Реализация.Дата КАК Дата
    |ПОМЕСТИТЬ ВТ_ВсеДокументы
    |ИЗ
    |    Документ.РеализацияТоваровУслуг КАК Реализация
    |ГДЕ
    |    Реализация.Дата МЕЖДУ &ПериодНачала И &ПериодОкончания
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |    ВТ.Ссылка КАК Ссылка
    |ПОМЕСТИТЬ ВТ_РазрешенныеДокументы
    |ИЗ
    |    ВТ_ВсеДокументы КАК ВТ
    |;
    |
    |////////////////////////////////////////////////////////////////////////////////
    |ВЫБРАТЬ
    |    Все.Ссылка КАК Ссылка,
    |    Все.Организация КАК Организация,
    |    Все.Номер КАК Номер,
    |    Все.Дата КАК Дата,
    |    ВЫБОР
    |        КОГДА Разрешенные.Ссылка ЕСТЬ NULL ТОГДА ЛОЖЬ
    |        ИНАЧЕ ИСТИНА
    |    КОНЕЦ КАК ДоступРазрешен
    |ИЗ
    |    ВТ_ВсеДокументы КАК Все
    |    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_РазрешенныеДокументы КАК Разрешенные
    |        ПО Все.Ссылка = Разрешенные.Ссылка";

    Запрос.УстановитьПараметр("ПериодНачала", ПериодНачала);
    Запрос.УстановитьПараметр("ПериодОкончания", ПериодОкончания);

    // Важно: первый шаг требует чтения всех данных, 
    // поэтому итоговую выборку получаем с учетом прав текущего сеанса
    ТаблицаРезультат = Запрос.Выполнить().Выгрузить();
    
    Возврат ТаблицаРезультат;

КонецФункции

Проанализируем особенности работы этого запроса: конструкция ВЫБРАТЬ РАЗРЕШЕННЫЕ во втором запросе автоматически отсекает все записи, не проходящие условия RLS для текущего сеанса. В третьем запросе соединение сопоставляет списки: если документ отсутствует в таблице разрешенных, в результирующей колонке ДоступРазрешен возвращается значение ЛОЖЬ.

Решение 2: Проверка одиночной ссылки через запрос

Если требуется выяснить доступность одного конкретного объекта (или небольшого списка ссылок), передадим эту ссылку параметром в запрос с ограничением прав:


Функция ДокументДоступенПользователю(СсылкаНаДокумент) Экспорт

    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ ПЕРВЫЕ 1
    |    1 КАК Поле
    |ИЗ
    |    Документ.РеализацияТоваровУслуг КАК ДокументТаблица
    |ГДЕ
    |    ДокументТаблица.Ссылка = &СсылкаНаДокумент";
    
    Запрос.УстановитьПараметр("СсылкаНаДокумент", СсылкаНаДокумент);
    
    РезультатЗапроса = Запрос.Выполнить();
    
    Возврат НЕ РезультатЗапроса.Пустой();

КонецФункции

Рассмотрим, как это работает: если RLS текущего пользователя запрещает чтение данного документа, запрос вернет пустой результат, и функция возвратит значение ЛОЖЬ. Если доступ есть — результат запроса содержит одну строку, функция вернет ИСТИНА.

Решение 3: Использование подсистемы «Управление доступом» (БСП)

Если конфигурация разработана на базе Библиотеки Стандартных Подсистем, в ней уже реализован программный интерфейс для работы с ограничениями прав.

Разберем методы общего модуля УправлениеДоступом:

  1. Проверка прав на конкретную ссылку или массив:
    
    // Проверка прав на чтение объекта
    ДоступЕсть = УправлениеДоступом.ДоступноЗначение(СсылкаНаОбъект);
    
    // Проверка права на чтение или изменение через общий интерфейс
    Если УправлениеДоступом.ЕстьПраво("Изменение", СсылкаНаОбъект) Тогда
        // Пользователь может редактировать документ с учетом RLS
    КонецЕсли;
    
  2. Получение доступных значений для фильтрации:
    
    // Получим список всех организаций, разрешенных пользователю
    МассивОрганизаций = УправлениеДоступом.ДоступныеЗначения(Метаданные.ОпределяемыеТипы.Организация);
    

Использование механизмов БСП предпочтительно в типовых конфигурациях (1С:ERP, 1С:КА, 1С:УТ, 1С:УНФ, 1С:ЗУП, 1С:Бухгалтерия), так как подсистема автоматически учитывает режим производительного RLS, кэширует права и работает с регистрами ключей доступа (КлючиДоступаКОбъектам, КлючиДоступаПользователей).

Решение 4: Точечная проверка через блок Попытка — Исключение

Для одиночной проверки в непривилегированном коде можно попытаться прочитать защищенные данные объекта напрямую. При попытке обращения к недоступному объекту платформа генерирует системное исключение.


Функция ПроверитьДоступЧерезИсключение(СсылкаНаОбъект) Экспорт

    Попытка
        // Пытаемся получить объект без привилегированного режима
        Объект = СсылкаНаОбъект.ПолучитьОбъект();
        Если Объект = Неопределено Тогда
            Возврат Ложь; // Объект помечен на удаление или не существует
        КонецЕсли;
        Возврат Истина;
    Исключение
        // Перехватываем ошибку "Нарушение прав доступа"
        Возврат Ложь;
    КонецПопытки;

КонецФункции

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

Нюансы RLS: ограничения на уровне отдельных полей

Обратим внимание на важную архитектурную деталь: RLS может быть настроен не на всю таблицу целиком, а на отдельные реквизиты (например, скрыто поле СуммаДокумента или табличная часть Товары).

В этом случае поведение конструкции ВЫБРАТЬ РАЗРЕШЕННЫЕ меняется:

  1. Сама строка документа по-прежнему будет попадать в выборку.
  2. В полях, чтение которых запрещено, платформа вернет значение NULL.

Поэтому, если требуется проверить доступ к закрытым полям документа, в секцию ВЫБРАТЬ РАЗРЕШЕННЫЕ запроса необходимо явно включать именно эти ограниченные реквизиты и выполнять проверку на NULL.

← На главную