Разработчики прикладных решений на платформе «1С:Предприятие 8» часто сталкиваются с ситуацией: в конфигурацию добавляется новый отчет на базе Системы компоновки данных (СКД). Для корректного обхода ограничений прав доступа (например, RLS или отсутствия у пользователя прямых прав на чтение некоторых таблиц) разработчик программно включает привилегированный режим непосредственно перед выводом отчета. Под полными правами все работает безукоризненно, но стоит запустить отчет под пользователем с ограниченными правами — и перед нами оказывается пустая таблица.
В рамках этой статьи мы подробно проанализируем, почему так происходит, изучим скрытые механизмы взаимодействия СКД с правами доступа и рассмотрим несколько путей решения данной проблемы, включая тот, который помог автору темы на форуме.
Рассмотрим стандартный подход к перехвату формирования отчета. В модуле объекта отчета переопределяется обработчик события ПриКомпоновкеРезультата:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
УстановитьПривилегированныйРежим(Истина);
ОтчетыПривилегированныйРежим.СформироватьОтчетПривилегированныйРежим(
ДокументРезультат,
СхемаКомпоновкиДанных,
ДанныеРасшифровки,
КомпоновщикНастроек,
Новый ТаблицаЗначений
);
КонецПроцедуры
Сама процедура генерации макета и вывода данных вынесена в общий модуль с включенным признаком Привилегированный:
Процедура СформироватьОтчетПривилегированныйРежим(ДокументРезультат, СхемаКомпоновкиДанных, ДанныеРасшифровки, КомпоновщикНастроек, ТаблицаДанных) Экспорт
ДокументРезультат.Очистить();
ПользовательскиеНастройкиМодифицированы = Ложь;
УстановитьОбязательныеНастройки(ПользовательскиеНастройкиМодифицированы, КомпоновщикНастроек);
НастройкиОтчета = КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// Выполнение компоновки макета
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки, , , Ложь);
КомпоновкаДанныхСервер.УстановитьЗаголовкиМакетаКомпоновки(
ПолучитьСтруктуруЗаголовковПолей(КомпоновщикНастроек),
МакетКомпоновки
);
ВнешнийНабор = Новый Структура("ТаблицаДанных", ТаблицаДанных);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешнийНабор, ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КомпоновкаДанныхСервер.СкрытьВспомогательныеПараметрыОтчета(СхемаКомпоновкиДанных, КомпоновщикНастроек, ДокументРезультат, ВспомогательныеПараметрыОтчета);
Если ПользовательскиеНастройкиМодифицированы Тогда
КомпоновщикНастроек.ПользовательскиеНастройки.ДополнительныеСвойства.Вставить("ПользовательскиеНастройкиМодифицированы", Истина);
КонецЕсли;
КонецПроцедуры
Несмотря на то, что вызов УстановитьПривилегированныйРежим(Истина) отрабатывает на сервере, а сам отчет компилируется в привилегированном модуле, обычный пользователь видит лишь пустую форму. Разберем ключевые причины этой проблемы.
Главная архитектурная особенность СКД заключается в том, что объект КомпоновщикНастроек инициализируется на клиенте (или в контексте обычного сеанса пользователя) и тесно связан с его правами доступа.
Когда пользователь открывает форму отчета, система анализирует его права на объекты метаданных, используемые в схеме компоновки. Если у пользователя нет прав на Просмотр определенных реквизитов, полей или таблиц БД, КомпоновщикНастроек автоматически выполняет следующие действия:
Когда управление передается на сервер в процедуру СформироватьОтчетПривилегированныйРежим, в метод ПолучитьНастройки() передается уже усеченная структура. Даже при активированном привилегированном режиме СКД выполняет пустой запрос, так как ключевые поля отбора и вывода были вырезаны еще на этапе инициализации формы.
Выясним еще одну важную деталь, упомянутую в ходе обсуждения. Платформа «1С:Предприятие» принудительно переключает исполнение кода в Безопасный режим, если в схеме компоновки данных используются вычисляемые поля или выражения ресурсов, вызывающие функции общих модулей.
В безопасном режиме действие любого привилегированного режима полностью блокируется платформой. Команда УстановитьПривилегированныйРежим(Истина) внутри безопасного контекста игнорируется, и система начинает проверять реальные права пользователя на уровне СУБД (включая RLS), что приводит к пустому результату или ошибкам доступа.
Это наиболее распространенная организационно-техническая проблема при разработке в базах на основе Библиотеки стандартных подсистем (БСП). Именно она стала причиной «пустого отчета» у автора темы.
БСП жестко контролирует доступ пользователей к отчетам и их вариантам через справочник Идентификаторы объектов метаданных. Если вы добавили новый отчет в конфигураторе или существенно изменили состав его реквизитов и прав доступа, но не обновили вспомогательные данные информационной базы, система под ограниченным пользователем не сможет правильно идентифицировать этот объект. В результате механизмы БСП блокируют выполнение запросов к метаданным, выдавая пустой результат без явных ошибок в журнале регистрации.
Как запустить обновление вспомогательных данных принудительно:
/C ЗапуститьОбновлениеИнформационнойБазы.
Справочники.ИдентификаторыОбъектовМетаданных.ОбновитьДанныеСправочника(Истина, Ложь);
ОбновлениеВспомогательныхДанных.epf из состава дистрибутива БСП, чтобы точечно обновить только измененные отчеты.Если специфика бизнес-логики требует, чтобы у пользователя вообще не было прав «Просмотр» на прикладные таблицы, стандартная схема СКД с набором данных типа «Запрос» работать не сможет из-за ограничений КомпоновщикаНастроек.
В этом случае рекомендуется использовать следующую архитектурную схему:
ТаблицаДанных).Таблицу Значений.Посмотрим на пример реализации заполнения внешнего набора данных:
// В модуле объекта отчета
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Получаем данные в привилегированном режиме без контроля прав
ТаблицаРезультата = ПолучитьДанныеВПривилегированномРежиме();
// Передаем таблицу в процессор компоновки
ВнешниеНаборыДанных = Новый Структура;
Внешние НаборыДанных.Вставить("ТаблицаДанных", ТаблицаРезультата);
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Если ваш встроенный отчет возвращает пустой результат под ограниченными правами, действуйте по следующему чек-листу:
КомпоновщикеНастроек.