Почему СКД требует право «Просмотр» при наличии «Чтения» и как обойти ограничения безопасного режима во внешних отчетах

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

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

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

Разбор полетов: Почему консоль запросов видит данные, а СКД — нет

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

  1. Чтение (Read): Разрешает чтение данных объекта программными методами и запросами на уровне СУБД. Именно это право проверяется при выполнении обычных SQL-подобных запросов.
  2. Просмотр (View): Разрешает интерактивное отображение данных в интерфейсе (в формах списков, формах выбора, отчетах и т.д.). Важно понимать, что «Просмотр» — это надстройка над «Чтением». Нельзя дать право на «Просмотр» без права на «Чтение».

Когда мы запускаем обычную консоль запросов, платформа выполняет прямой запрос к базе данных под правами текущего пользователя. Для СУБД этого абсолютно достаточно: у пользователя есть право Чтение, ограничения RLS (если они настроены) отрабатывают на уровне СУБД, и консоль выводит «сырые» данные в свою таблицу на форме.

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

Почему не сработал привилегированный режим во внешнем отчете

Вторая загадка, с которой столкнулся автор темы: почему система проигнорировала вызов функции УстановитьПривилегированныйРежим(Истина) в процедуре ПриКомпоновкеРезультата? Ведь привилегированный режим должен полностью отключать проверку прав, включая RLS и проверку доступности полей.

Причина кроется в способе запуска отчета. Автор открывал его интерактивно через меню Файл — Открыть как внешний отчет. По соображениям безопасности платформа 1С:Предприятие запускает любые внешние обработки и отчеты, открытые таким способом, в так называемом безопасном режиме.

В безопасном режиме платформа накладывает жесткие ограничения на выполнение кода:

Именно поэтому попытка включить привилегированный режим «внутри» внешнего отчета, открытого небезопасным (с точки зрения платформы) способом, обречена на провал.

Как решить проблему: Три практических варианта

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

Вариант А. Программный обход проверки прав в СКД («Секретные флажки»)

Если у пользователя физически есть право Чтение на данные, но у него нет (и не должно быть) права Просмотр, мы можем заставить СКД проигнорировать проверку интерактивных прав. Для этого нам потребуется отказаться от стандартного вывода отчета и сформировать его программно в процедуре ПриКомпоновкеРезультата модуля объекта отчета.

В платформе 1С существуют два важнейших параметра для отключения проверок прав при компоновке данных. Рассмотрим их применение на практике:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    // 1. Отключаем стандартный вывод отчета платформой
    СтандартнаяОбработка = Ложь; 
    
    // 2. Получаем текущие настройки пользователя
    НастройкиОтчета = КомпоновщикНастроек.ПолучитьНастройки();
    
    // 3. Создаем компоновщик макета
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    
    // Используем ПЕРВЫЙ секретный флаг: "ПроверятьДоступностьПолей" (6-й параметр метода Выполнить)
    // Устанавливаем его в значение Ложь. Это заставит СКД не проверять права на "Просмотр"
    МакетКомпоновки = КомпоновщикМакета.Выполнить(
        СхемаКомпоновкиДанных, 
        НастройкиОтчета, 
        ДанныеРасшифровки, 
        , // Макет оформления по умолчанию
        , // Тип генератора макета по умолчанию
        Ложь // ПроверятьДоступностьПолей = Ложь
    );
    
    // 4. Инициализируем процессор компоновки данных
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    
    // Используем ВТОРОЙ секретный флаг: "ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр" (5-й параметр метода Инициализировать)
    // Устанавливаем его в Ложь, чтобы платформа разрешила разыменование ссылок без права Просмотр на связанные таблицы
    ПроцессорКомпоновки.Инициализировать(
        МакетКомпоновки, 
        , // Внешние наборы данных (если есть)
        ДанныеРасшифровки, 
        Истина, // Возможность использования внешних функций
        Ложь    // ОграничиватьПолучениеПолейПоСсылкамПоПравуПросмотр = Ложь
    );
    
    // 5. Выводим результат в табличный документ
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

При таком подходе СКД не будет отсекать поля на этапе компоновки макета, и, поскольку у пользователя есть физическое право Чтение, данные успешно отобразятся в отчете.

Вариант Б. Отключение безопасного режима для внешнего отчета (через БСП)

Если ваша конфигурация разработана на базе Библиотеки стандартных подсистем (БСП), вам категорически не рекомендуется открывать внешние отчеты через обычное меню «Файл — Открыть». Правильный путь — зарегистрировать отчет в справочнике ДополнительныеОтчетыИОбработки.

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

Рассмотрим пример заполнения этой функции:


Функция СведенияОВнешнейОбработке() Экспорт
    
    ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.3");
    
    ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительныйОтчет();
    ПараметрыРегистрации.Наименование = "Мой безопасный отчет с обходом RLS";
    ПараметрыРегистрации.Версия = "1.0";
    ПараметрыРегистрации.БезопасныйРежим = Ложь; // Важнейшая строка: запрашиваем отключение безопасного режима
    
    // Для новых версий БСП также рекомендуется явно запрашивать разрешение на использование привилегированного режима:
    ПрограммаЗапроса = Новый Массив;
    // Здесь при необходимости добавляются конкретные разрешения программного интерфейса БСП
    ПараметрыРегистрации.Разрешения = ПрограммаЗапроса;
    
    // Определение команд отчета
    НоваяКоманда = ПараметрыРегистрации.Команды.Добавить();
    НоваяКоманда.Представление = "Открыть отчет";
    НоваяКоманда.Идентификатор = "ОткрытьОтчет";
    НоваяКоманда.Использование = ДополнительныеОтчетыИОбработкиКлиентСервер.ТипЗапускаОткрытиеФормы();
    
    Возврат ПараметрыРегистрации;
    
КонецФункции

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

Вариант В. Вынос получения данных в привилегированный общий модуль

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

Для этого мы можем использовать следующий алгоритм:

  1. Создаем в конфигураторе новый общий модуль (например, _ПривилегированныйВызовПереопределяемый). Устанавливаем ему свойства: Клиент (сервер), Сервер и обязательно флаг Привилегированный.
  2. В этом модуле пишем экспортную функцию, которая выполняет запрос к данным и возвращает результат в виде таблицы значений.
  3. В СКД нашего внешнего отчета настраиваем источник данных типа Набор данных - объект.
  4. В модуле внешнего отчета в процедуре ПриКомпоновкеРезультата вызываем функцию нашего общего модуля, получаем готовую таблицу значений и передаем её в СКД в качестве внешнего набора данных.

Посмотрим на пример реализации такого подхода.

Код в общем привилегированном модуле конфигурации:


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

Код в модуле объекта внешнего отчета (набор данных-объект назван "ТаблицаДокументов"):


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

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

← На главную