При настройке прав доступа на уровне записей (RLS) разработчики часто сталкиваются с задачей сопоставления полей документов или справочников с реквизитами текущего пользователя — например, для ограничения видимости данных по числовому уровню доступа, подразделению или филиалу.
Попытка напрямую обратиться через точку к реквизиту параметра сеанса, например (&ТекущийПользователь).УровеньДоступа или &ТекущийПользователь.УровеньДоступа, приводит к синтаксической ошибке. Разберем причины такого поведения платформы и подробно рассмотрим все способы реализации данной задачи.
В языке запросов платформы 1С:Предприятие обращение через точку к реквизитам нетипизированного параметра невозможно. На этапе синтаксического анализа и компиляции шаблона RLS тип переданного параметра сеанса неизвестен транслятору запросов. Поэтому конструкция &Параметр.Реквизит не распознается как валидное поле базы данных.
Для реализации логики фильтрации существует три основных подхода: вынесение значения в отдельный параметр сеанса, явное приведение типа параметра через конструкцию ВЫРАЗИТЬ и соединение с таблицей справочника пользователей.
Наиболее производительным и архитектурно правильным решением является вычисление значения реквизита при старте сеанса и сохранение его в отдельный скалярный параметр сеанса.
Разберем по шагам, как это настроить:
ТекущийУровеньДоступа с числовым типом.УстановкаПараметровСеанса:
Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
Если ТребуемыеПараметры = Неопределено
Или ТребуемыеПараметры.Найти("ТекущийУровеньДоступа") <> Неопределено Тогда
Если ЗначениеЗаполнено(ПараметрыСеанса.ТекущийПользователь) Тогда
ПараметрыСеанса.ТекущийУровеньДоступа = ПараметрыСеанса.ТекущийПользователь.УровеньДоступа;
Иначе
ПараметрыСеанса.ТекущийУровеньДоступа = 0;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
ГДЕ
ЕСТЬNULL(Организация.УровеньДоступа, 0) < &ТекущийУровеньДоступа
Преимущества подхода: СУБД подставляет в предикат SQL простое константное значение. Запрос не содержит лишних соединений со справочником пользователей, что обеспечивает максимальное быстродействие при чтении динамических списков и проведении документов.
Часто возникает опасение, что добавление новых параметров сеанса замедлит запуск фоновых заданий и построение отчетов. Проанализируем этот момент: фоновое задание выполняется в отдельном серверном сеансе, где при старте также вызывается обработчик УстановкаПараметровСеанса.
Чтобы инициализация не влияла на скорость запуска фоновых потоков, используем инициализацию «по требованию» (ленивую инициализацию): инициализируем параметр только тогда, когда его имя присутствует в массиве ТребуемыеПараметры. Если фоновое задание работает в привилегированном режиме (УстановитьПривилегированныйРежим(Истина)), RLS не применяется, и параметр сеанса вовсе не будет рассчитываться.
Если конфигурация находится на поддержке без возможности добавления новых метаданных, укажем тип параметра непосредственно в тексте запроса RLS с помощью оператора ВЫРАЗИТЬ:
ГДЕ
ЕСТЬNULL(Организация.УровеньДоступа, 0) < ВЫРАЗИТЬ(&ТекущийПользователь КАК Справочник.Пользователи).УровеньДоступа
После явного указания типа Справочник.Пользователи платформа сможет обратиться к реквизиту УровеньДоступа. Под капотом СУБД автоматически выполнит неявное левое соединение со справочником пользователей.
Другой способ обхода без добавления параметров — использование явного соединения или подзапроса в тексте RLS:
ДокументПродажи ИЗ Документ.РеализацияТоваровУслуг КАК ДокументПродажи
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи
ПО Пользователи.Ссылка = &ТекущийПользователь
И ЕСТЬNULL(ДокументПродажи.Организация.УровеньДоступа, 0) < ЕСТЬNULL(Пользователи.УровеньДоступа, 0)
Или через условие в секции ГДЕ с подзапросом:
ГДЕ
ЕСТЬNULL(Организация.УровеньДоступа, 0) < (
ВЫБРАТЬ ПЕРВЫЕ 1
ЕСТЬNULL(Пользователи.УровеньДоступа, 0)
ИЗ
Справочник.Пользователи КАК Пользователи
ГДЕ
Пользователи.Ссылка = &ТекущийПользователь
)
Обратите внимание: Способы с соединениями и подзапросами создают дополнительную нагрузку на СУБД при выборке больших объемов данных. Для высоконагруженных систем предпочтительным остается Способ 1 с вычислением скалярного значения в параметре сеанса.
В языке запросов 1С любые операции сравнения с неопределенным значением NULL возвращают результат Ложь. Если у организации или пользователя не заполнен реквизит уровня доступа, документ окажется скрыт от пользователя.
Чтобы избежать ошибок доступа, всегда оборачивайте числовые реквизиты в функцию ЕСТЬNULL(Поле, 0) в условиях ограничений RLS.