При разработке внешних обработок в системе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда механизмы RLS (Record Level Security) блокируют доступ к необходимым данным. Особенно остро это проявляется в конфигурациях вроде «1С:Розница» или «1С:Управление торговлей», где права жестко ограничены по магазинам или складам. Рассмотрим ситуацию: нам нужно вывести остатки по всем складам в динамическом списке, но текущему пользователю разрешен просмотр только своего магазина. В этой статье мы подробно разберем, почему стандартный привилегированный режим не спасает, и какими способами можно элегантно решить эту задачу.
Прежде чем переходить к решениям, проанализируем причину неудачи. Метод УстановитьПривилегированныйРежим(Истина) отлично работает в серверных процедурах при выполнении запросов или записи объектов. Однако Динамический список — это особый объект платформы. Когда форма открывается, платформа формирует SQL-запрос к базе данных от имени текущего пользователя. Даже если вы вызвали привилегированный режим в процедуре ПриСозданииНаСервере, он прекращает свое действие сразу после завершения этой процедуры. Как только управление возвращается платформе для отрисовки интерфейса и получения данных для списка, запрос уходит в БД уже с наложенными условиями RLS.
Более того, для внешних обработок существует понятие Безопасного режима. В этом режиме метод повышения прав просто игнорируется платформой из соображений безопасности. Разберем шаги, которые помогут нам обойти эти ограничения.
Это самый современный и производительный метод, доступный в платформе 8.3.10 и выше. Суть метода заключается в том, что мы позволяем динамическому списку получить основной массив данных (например, список номенклатуры), а затем «дозаполняем» нужные колонки (остатки на центральном складе) в привилегированном режиме.
Разберем алгоритм реализации по шагам:
ОстатокНаЦентральномСкладе), которая не связана с основным запросом (путь к данным не заполняем).ПриПолученииДанныхНаСервере.Рассмотрим пример кода для формы обработки:
&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
// Получаем массив ссылок на номенклатуру из текущей порции данных списка
МассивНоменклатуры = Новый Массив;
Для Каждого СтрокаСписка Из Строки Цикл
МассивНоменклатуры.Добавить(СтрокаСписка.Ключ);
КонецЦикла;
// Вызываем функцию, которая работает в привилегированном режиме
ТаблицаОстатков = ПолучитьОстаткиПривилегированно(МассивНоменклатуры);
// Заполняем колонки в строках динамического списка
Для Каждого СтрокаСписка Из Строки Цикл
ДанныеСтроки = ТаблицаОстатков.Найти(СтрокаСписка.Ключ, "Номенклатура");
Если ДанныеСтроки <> Неопределено Тогда
СтрокаСписка.Данные["ОстатокНаЦентральномСкладе"] = ДанныеСтроки.Остаток;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
&НаСервере
Функция ПолучитьОстаткиПривилегированно(МассивНоменклатуры)
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
| ТоварыНаСкладахОстатки.ВНаличииОстаток КАК Остаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад = &ЦентральныйСклад И Номенклатура В (&МассивНоменклатуры)) КАК ТоварыНаСкладахОстатки";
Запрос.УстановитьПараметр("ЦентральныйСклад", Справочники.Склады.НайтиПоНаименованию("Центральный"));
Запрос.УстановитьПараметр("МассивНоменклатуры", МассивНоменклатуры);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
Преимущество данного метода заключается в том, что запрос выполняется только для тех 30-40 строк, которые пользователь видит на экране в данный момент. Это не нагружает систему и позволяет обойти RLS точечно.
Если вы используете механизм «Дополнительные отчеты и обработки» (БСП), то по умолчанию все обработки запускаются в безопасном режиме. Чтобы метод УстановитьПривилегированныйРежим(Истина) сработал внутри серверного модуля обработки, необходимо явно указать параметры регистрации.
Проанализируем функцию СведенияОВнешнейОбработке:
Функция СведенияОВнешнейОбработке() Экспорт
ПараметрыРегистрации = ДополнительныеОтчетыИОбработки.СведенияОВнешнейОбработке("2.2.2.1");
ПараметрыРегистрации.Вид = ДополнительныеОтчетыИОбработкиКлиентСервер.ВидОбработкиДополнительнаяОбработка();
ПараметрыРегистрации.Наименование = "Подбор номенклатуры (Привилегированный)";
// ВАЖНО: Устанавливаем Ложь для возможности использования привилегированного режима
ПараметрыРегистрации.БезопасныйРежим = Ложь;
// Далее заполняем команды...
Возврат ПараметрыРегистрации;
КонецФункции
После загрузки такой обработки в информационную базу администратор должен подтвердить разрешение на выполнение потенциально опасных действий. Только после этого код внутри обработки сможет игнорировать RLS через вызов соответствующих процедур.
Если специфика задачи позволяет, наиболее архитектурно правильным решением будет вынос логики получения данных в Расширение. В расширении можно создать общий модуль с установленным флажком «Привилегированный».
Рассмотрим преимущества этого подхода:
Если объем данных невелик (например, несколько сотен позиций номенклатуры), можно отказаться от ДинамическогоСписка в пользу ТаблицыЗначений. В этом случае мы полностью контролируем процесс получения данных.
Выясним, как это реализовать:
ДинамическийСписок создаем реквизит формы типа ТаблицаЗначений с нужными колонками.ПриСозданииНаСервере вызываем запрос в привилегированном режиме.Однако стоит помнить, что при работе с сотнями тысяч записей этот метод может привести к зависанию интерфейса и избыточному потреблению оперативной памяти, так как все данные будут переданы с сервера на клиент.
Проанализировав ситуацию, мы можем сделать следующие выводы:
Если вам нужно оставить интерфейс подбора быстрым и удобным (с поиском и отборами динамического списка), используйте Решение №1 (событие ПриПолученииДанныхНаСервере) в сочетании с Решением №2. Это обеспечит максимальную производительность и решит проблему отображения «запрещенных» остатков.
Если задача разовая и данных мало — подойдет Решение №4. Для долгосрочных проектов и тиражируемых решений лучше всего использовать Расширения (Решение №3), так как это минимизирует риски при обновлениях конфигурации и обеспечивает наиболее стабильную работу механизмов прав доступа.
Важный нюанс: Никогда не возвращайте из привилегированных функций ссылки на документы или склады, к которым у пользователя нет прав доступа «на чтение» в принципе. Это может вызвать ошибки при попытке системы отрисовать представление ссылки в интерфейсе. Лучше возвращать строковые представления или числовые показатели (остатки, цены).