Как в обычных формах 1С записать объект в привилегированном режиме, если не хватает прав?

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

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

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

Почему метод не работает на стороне клиента?

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

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

Интересный нюанс: если мы тестируем этот же код в файловой базе данных, то исходный код в обычной форме может отработать успешно, так как в файловом варианте работы привилегированный режим можно включить и на клиенте. Но при переносе в рабочую клиент-серверную базу код перестанет работать.

Правильное решение: перенос логики на сервер

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

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

Как правильно передавать данные на сервер

Разберем самую частую ошибку начинающих разработчиков при переходе на эту методику. Это попытка передать готовый измененный объект, то есть СправочникОбъект, с клиента на сервер для простой записи.

Передавать нужно только Ссылки (например, ссылку на номенклатуру, ссылку на новую папку-родителя) и другие примитивные типы данных (числа, строки, булево). А непосредственно внутри серверной процедуры мы должны вызвать метод ПолучитьОбъект(), изменить необходимые реквизиты и произвести запись.

Пример архитектуры решения в коде

Посмотрим на пример, как должен выглядеть наш код после рефакторинга.

Код в модуле обычной формы (выполняется на клиенте):


Для Каждого Стр Из ЭтотОбъект.НоменклатурныеПозиции Цикл
    Если Стр.Переносить = Истина Тогда
        // Вызываем серверную экспортную процедуру, передаем только ссылки
        НоменклатураПривилегированный.ПеренестиНоменклатуруВПапку(Стр.Номенклатура, ЭтотОбъект.Родитель);
    КонецЕсли;
КонецЦикла;

Код в Общем модуле (Свойства: Сервер, Вызов сервера, Привилегированный):


Процедура ПеренестиНоменклатуруВПапку(СсылкаНоменклатуры, СсылкаНоваяПапка) Экспорт
    
    // В этом модуле платформа уже не проверяет права текущего пользователя
    ОбъектНоменклатуры = СсылкаНоменклатуры.ПолучитьОбъект();
    
    Если ОбъектНоменклатуры <> Неопределено Тогда
        ОбъектНоменклатуры.Родитель = СсылкаНоваяПапка;
        ОбъектНоменклатуры.Записать();
    КонецЕсли;
    
КонецПроцедуры

Вопросы безопасности и проектирования

В завершение обсудим важный аспект безопасности. При создании привилегированных модулей стандартами разработки 1С категорически запрещается создавать универсальные функции для записи всего подряд. Например, процедура вида ЗаписатьЛюбойОбъектБезПрав(ЛюбаяСсылка) создает огромную «дыру» в безопасности системы. Через такой код хитрая внешняя обработка сможет изменить любые критичные данные (например, зарплатные ведомости) от лица менеджера.

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

← На главную