Как реализовать работу отчета СКД в привилегированном режиме и обойти ограничения прав доступа

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

При разработке отчетов на платформе 1С:Предприятие 8 часто возникает ситуация, когда пользователю необходимо вывести данные, на которые у него нет прямых прав (например, расчетчику планирования нужны данные по окладам из кадровых документов). Попытка просто вызвать УстановитьПривилегированныйРежим(Истина) в модуле объекта часто не приносит результата, так как система компоновки данных (СКД) имеет свои механизмы проверки прав и ограничений RLS (Record Level Security). Разберем детально, почему это происходит и какими способами можно добиться желаемого результата.

Почему стандартный подход не работает?

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

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

Способ 1. Программное формирование отчета на сервере

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

Для реализации этого метода в модуле объекта отчета необходимо использовать событие ПриКомпоновкеРезультата. Разберем по шагам пример кода:


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

&НаСервере
Процедура СформироватьОтчетПривилегированно(ТабДок, ДанныеРасшифровки, Схема, Настройки)
    
    УстановитьПривилегированныйРежим(Истина);
    
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(Схема, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ТабДок);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Обратите внимание на четвертый параметр метода Инициализировать процессора компоновки — передача Истина позволяет использовать внешние функции в запросах, но ключевым здесь является именно серверный контекст с установленным режимом. Однако, даже этот способ иногда может выдавать "Объект не найден", если у пользователя нет прав на чтение ссылочных полей. Выясним, как это обойти ниже.

Способ 2. Использование набора данных "Объект" (Таблица значений)

Этот вариант считается "золотым стандартом", если нужно полностью абстрагироваться от прав доступа 1С. Мы разделяем получение данных и их визуализацию. Выясним причину эффективности этого метода: СКД не проверяет права RLS на данные, которые уже находятся в оперативной памяти в виде ТаблицаЗначений.

Посмотрим на алгоритм действий:

  1. Создаем в СКД набор данных типа Объект и называем его, например, ТаблицаДанных.
  2. В коде модуля объекта отчета формируем запрос в привилегированном режиме.
  3. Выгружаем результат запроса в таблицу значений.
  4. Передаем эту таблицу в процессор компоновки как внешний набор данных.

Пример реализации в модуле объекта:


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

Как избежать надписи "Объект не найден"?

Проанализируем ситуацию: отчет сформирован в привилегированном режиме, данные получены, но пользователь вместо фамилий сотрудников видит <Объект не найден>. Это происходит потому, что при выводе ссылки в ТабличныйДокумент платформа пытается получить Представление объекта от имени текущего пользователя. Если прав на чтение объекта нет — представление не строится.

Решение: В тексте запроса или при формировании таблицы значений заменяйте ссылки на их строковые представления. Используйте функцию ПРЕДСТАВЛЕНИЕ(ПолеСсылка) или заранее получайте нужные реквизиты (Наименование, ФИО) в виде строк. В этом случае СКД будет выводить обычный текст, который не требует проверки прав при отрисовке ячейки.

Особенности для внешних отчетов

Если ваш отчет подключается как дополнительная обработка, обязательно выполните следующие шаги:

  1. В справочнике "Дополнительные отчеты и обработки" найдите ваш отчет.
  2. Установите режим выполнения в "Небезопасный". В противном случае платформа заблокирует любые попытки повышения привилегий кода.
  3. Для программного формирования используйте общий модуль с признаком Привилегированный, если отчет встроен в конфигурацию, или методы серверного модуля объекта, если отчет внешний.

Альтернатива: Регламентные и фоновые задания

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

Подведем итог: Для реализации привилегированного режима в СКД недостаточно просто вызвать одну функцию. Необходимо либо программно выводить отчет на сервере, передавая готовый ТабличныйДокумент, либо использовать Набор данных - объект, предварительно подготовив данные в виде таблицы значений. Второй способ является наиболее универсальным, так как он "разрывает" связь между правами доступа к таблицам базы данных и выводом информации в отчет.

← На главную