Как в условии RLS обратиться к реквизиту текущего пользователя?

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

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

Попытка напрямую обратиться через точку к реквизиту параметра сеанса, например (&ТекущийПользователь).УровеньДоступа или &ТекущийПользователь.УровеньДоступа, приводит к синтаксической ошибке. Разберем причины такого поведения платформы и подробно рассмотрим все способы реализации данной задачи.

Почему прямая запись через точку не работает

В языке запросов платформы 1С:Предприятие обращение через точку к реквизитам нетипизированного параметра невозможно. На этапе синтаксического анализа и компиляции шаблона RLS тип переданного параметра сеанса неизвестен транслятору запросов. Поэтому конструкция &Параметр.Реквизит не распознается как валидное поле базы данных.

Для реализации логики фильтрации существует три основных подхода: вынесение значения в отдельный параметр сеанса, явное приведение типа параметра через конструкцию ВЫРАЗИТЬ и соединение с таблицей справочника пользователей.

Способ 1. Создание отдельного параметра сеанса (рекомендуемый)

Наиболее производительным и архитектурно правильным решением является вычисление значения реквизита при старте сеанса и сохранение его в отдельный скалярный параметр сеанса.

Разберем по шагам, как это настроить:

  1. В дереве метаданных в ветке Параметры сеанса добавим новый параметр, например, ТекущийУровеньДоступа с числовым типом.
  2. В модуле сеанса настроим инициализацию нового параметра в процедуре УстановкаПараметровСеанса:

Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
    
    Если ТребуемыеПараметры = Неопределено 
        Или ТребуемыеПараметры.Найти("ТекущийУровеньДоступа") <> Неопределено Тогда
        
        Если ЗначениеЗаполнено(ПараметрыСеанса.ТекущийПользователь) Тогда
            ПараметрыСеанса.ТекущийУровеньДоступа = ПараметрыСеанса.ТекущийПользователь.УровеньДоступа;
        Иначе
            ПараметрыСеанса.ТекущийУровеньДоступа = 0;
        КонецЕсли;
        
    КонецЕсли;
    
КонецПроцедуры
  1. В тексте ограничения доступа (RLS) для нужного объекта пропишем простое условие:

ГДЕ
    ЕСТЬNULL(Организация.УровеньДоступа, 0) < &ТекущийУровеньДоступа

Преимущества подхода: СУБД подставляет в предикат SQL простое константное значение. Запрос не содержит лишних соединений со справочником пользователей, что обеспечивает максимальное быстродействие при чтении динамических списков и проведении документов.

Влияние параметров сеанса на фоновые задания

Часто возникает опасение, что добавление новых параметров сеанса замедлит запуск фоновых заданий и построение отчетов. Проанализируем этот момент: фоновое задание выполняется в отдельном серверном сеансе, где при старте также вызывается обработчик УстановкаПараметровСеанса.

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

Способ 2. Использование явного приведения типа (ВЫРАЗИТЬ)

Если конфигурация находится на поддержке без возможности добавления новых метаданных, укажем тип параметра непосредственно в тексте запроса RLS с помощью оператора ВЫРАЗИТЬ:


ГДЕ
    ЕСТЬNULL(Организация.УровеньДоступа, 0) < ВЫРАЗИТЬ(&ТекущийПользователь КАК Справочник.Пользователи).УровеньДоступа

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

Способ 3. Явное соединение с таблицей пользователей

Другой способ обхода без добавления параметров — использование явного соединения или подзапроса в тексте RLS:


ДокументПродажи ИЗ Документ.РеализацияТоваровУслуг КАК ДокументПродажи
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Справочник.Пользователи КАК Пользователи
    ПО Пользователи.Ссылка = &ТекущийПользователь
        И ЕСТЬNULL(ДокументПродажи.Организация.УровеньДоступа, 0) < ЕСТЬNULL(Пользователи.УровеньДоступа, 0)

Или через условие в секции ГДЕ с подзапросом:


ГДЕ
    ЕСТЬNULL(Организация.УровеньДоступа, 0) < (
        ВЫБРАТЬ ПЕРВЫЕ 1
            ЕСТЬNULL(Пользователи.УровеньДоступа, 0)
        ИЗ
            Справочник.Пользователи КАК Пользователи
        ГДЕ
            Пользователи.Ссылка = &ТекущийПользователь
    )

Обратите внимание: Способы с соединениями и подзапросами создают дополнительную нагрузку на СУБД при выборке больших объемов данных. Для высоконагруженных систем предпочтительным остается Способ 1 с вычислением скалярного значения в параметре сеанса.

Обработка значений NULL

В языке запросов 1С любые операции сравнения с неопределенным значением NULL возвращают результат Ложь. Если у организации или пользователя не заполнен реквизит уровня доступа, документ окажется скрыт от пользователя.

Чтобы избежать ошибок доступа, всегда оборачивайте числовые реквизиты в функцию ЕСТЬNULL(Поле, 0) в условиях ограничений RLS.

← На главную