Как обойти ограничение доступа на уровне записей (RLS) при выборе данных в конкретном документе?

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

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

Разберем детально, почему стандартные попытки включения привилегированного режима не работают для форм выбора, к каким утечкам данных может привести манипуляция параметрами сеанса и как правильно реализовать выбор недоступных по RLS данных без компрометации безопасности системы.

Анализ проблемы: почему не работает стандартный подход

Рассмотрим типовые ошибки, которые часто допускают разработчики при попытке решить эту задачу:

  1. Использование привилегированного режима при открытии формы: вызов метода УстановитьПривилегированныйРежим(Истина) выполняется исключительно в серверном контексте и сбрасывается платформой в момент возврата управления на клиент. Открыть интерактивную форму на сервере невозможно.
  2. Динамические списки игнорируют привилегированный контекст: стандартная форма выбора справочника функционирует на основе ДинамическийСписок. Запросы динамического списка компилируются платформой с обязательным автоматическим наложением ограничений RLS текущего сеанса. Привилегированный режим на динамический список формы не распространяется.
  3. Изменение параметров сеанса ломает права во всей системе: если попытаться временно перезаписать параметры сеанса, на которых строятся условия RLS, эти параметры изменятся глобально для всей сессии пользователя. В результате, пока открыт документ кадрового перемещения, пользователь может сформировать любой отчет и увидеть конфиденциальные данные чужих подразделений.

Способ 1. Создание кастомной формы выбора на основе таблицы значений

Проанализируем наиболее надежное и масштабируемое решение: отказ от динамического списка в форме выбора в пользу ТаблицаЗначений или ДеревоЗначений, заполняемых в привилегированном режиме.

Разберем по шагам реализацию этого механизма:

  1. Создаем отдельную форму выбора для справочника (например, ФормаВыбораБезRLS).
  2. Вместо стандартного динамического списка добавляем реквизит формы СписокПодразделений с типом ТаблицаЗначений (или ДеревоЗначений для иерархии) и выводим его в элементы формы.
  3. Заполняем таблицу значений запросом на сервере с явным включением привилегированного режима либо через привилегированный общий модуль.
  4. В форме исходного документа перехватываем событие начала выбора реквизита.

Посмотрим на пример перехвата события в форме документа:


&НаКлиенте
Процедура ПодразделениеПолучательНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    ПараметрыОткрытия = Новый Структура;
    ПараметрыОткрытия.Вставить("ЗакрыватьПриВыборе", Истина);
    
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораПодразделения", ЭтотОбъект);
    ОткрытьФорму("Справочник.ПодразделенияОрганизаций.Форма.ФормаВыбораБезRLS", ПараметрыОткрытия, Элемент, , , , Оповещение);

КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораПодразделения(РезультатВыбора, ДополнительныеПараметры) Экспорт

    Если ЗначениеЗаполнено(РезультатВыбора) Тогда
        Объект.ПодразделениеПолучатель = РезультатВыбора;
    КонецЕсли;

КонецПроцедуры

Теперь рассмотрим серверный код инициализации кастомной формы выбора, где выполняется чтение данных без учета RLS:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    ЗаполнитьТаблицуВыбора();

КонецПроцедуры

&НаСервере
Процедура ЗаполнитьТаблицуВыбора()
    
    УстановитьПривилегированныйРежим(Истина);
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |	Подразделения.Ссылка КАК Ссылка,
        |	Подразделения.Наименование КАК Наименование
        |ИЗ
        |	Справочник.ПодразделенияОрганизаций КАК Подразделения
        |ГДЕ
        |	НЕ Подразделения.ПометкаУдаления
        |УПОРЯДОЧИТЬ ПО
        |	Подразделения.Наименование";
        
    ТаблицаРезультат = Запрос.Выполнить().Выгрузить();
    
    // Возвращаем штатный режим доступа сразу после получения выборки
    УстановитьПривилегированныйРежим(Ложь);
    
    ЗначениеВРеквизитФормы(ТаблицаРезультат, "СписокПодразделений");

КонецПроцедуры

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


&НаКлиенте
Процедура СписокПодразделенийВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    
    ТекущиеДанные = Элементы.СписокПодразделений.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        ОповеститьОВыборе(ТекущиеДанные.Ссылка);
    КонецЕсли;

КонецПроцедуры

Способ 2. Заполнение выпадающего списка выбора через привилегированный модуль

Если справочник содержит небольшое количество элементов (например, филиалы или дирекции), можно обойтись без создания отдельной формы выбора. Задействуем механизм быстрого выбора из списка значений.

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


&НаКлиенте
Процедура ПодразделениеПолучательНачалоВыбора(Элемент, ДанныеВыбора, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    Список = ПолучитьСписокПодразделенийНаСервере();
    
    // Показываем пользователю локальный список выбора
    Элемент.СписокВыбора.Очистить();
    Элемент.СписокВыбора.ЗагрузитьЗначения(Список);

КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьСписокПодразделенийНаСервере()
    
    // Вызов функции привилегированного общего модуля
    Возврат ПолныеПрава.ПолучитьВсеПодразделения();

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

В модуле ПолныеПрава (с установленным свойством «Привилегированный») формируем выборку ссылок без ограничений прав:


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

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

Важный нюанс: проведение и запись документа

Обратите внимание: обойти RLS только на этапе интерактивного выбора подразделения недостаточно. В момент, когда пользователь попытается записать или провести документ, сработает контроль прав на запись связанных регистров сведений и регистров накопления (например, кадровых срезов), куда будет передана ссылка на недоступное подразделение.

Чтобы исключить исключительные ситуации нарушения прав доступа при проведении документа:

  1. Выполняйте процедуру ОбработкаПроведения в модуле документа с включением привилегированного режима через УстановитьПривилегированныйРежим(Истина).
  2. Если логика проведения вынесена в общие модули, переносите движения регистров по закрытым подразделениям в модуль с признаком Привилегированный.
  3. Проверьте права на чтение самого документа: если документ содержит закрытое подразделение, шаблон RLS на документ КадровоеПеремещение должен разрешать чтение этого документа инициатором перемещения.
← На главную