Книга знаний

Рекламное место пустует
1С:Предприятие / v8 / Объекты конфигурации

v8: Как определить, что запись вызвана программно (из привилегированного модуля)

Как сообщить объекту, что его нужно записать без контроля прав доступа.Автор статьи: Гений 1С | Редакторы: Волшебник
Последняя редакция №9 от 29.06.06 | История
URL: http://kb.mista.ru/article.php?id=132

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

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

Поэтому в процедуре ПередЗаписью при контроле прав доступа важно знать, работаем ли мы из привелигированного модуля или нет.

Исследования показали, что если создать не доступный ни одной роли объект, например константу, то в привелигированном модуле право "Чтение" становится доступным, кроме того, если процедура вызвана из привелигированного модуля, то право "Чтение" все еще доступно. Т.е. открываются все права, пока работает привелигированный модуль. Теперь достаточно проверить право доступа к этому объекту и становится понятным, работаем ли мы из привелигированного модуля.

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


Далее, заводим какую-нибудь служебную константу, например п_ДляКонтроляПравДоступаПривилегированногоМодуля, отключаем доступ к ней у всех пользователей.

Далее в общем непривилегерованном модуле объявляем функцию:
Функция РаботаетПривилегированныйМодуль() Экспорт

    Возврат ПравоДоступа ("Чтение", Метаданные.Константы.п_ДляКонтроляПравДоступаПривилегированногоМодуля);
КонецФункции;


У объекта, у которого нужно отличать программную запись от интерактивной меняем в процедуре ПередЗаписью код:
Процедура ПередЗаписью(Отказ, Режим записи, Режим проведения) Экспорт
    Если РаботаетПривилегированныйМодуль() Тогда
        Возврат;
    КонецЕсли;
    //Дальше идет код проверки при интерактивном доступе
КонецПроцедуры


Ну и наконец, чтобы отметить именно программный вызов записи, пишем не Объект.Записать(), а ЗаписатьПрограммно(Объект).

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

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

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

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

Функция должна возвращать ссылку на записанный новый объект.

Накладные расходы мизерны, потому что:
= Привелигированная запись нужна не часто.
= Обращение к базе данных идет гораздо дольше обращения к метаданным и разложения объекта.

Желающие могут поэкспериментировать c XML-серилизацией, но это будет дольше разложения в структуру.
Функции ЗначениеВСтрокуВнутр, ЗначениеИзСтрокиВнутр не преобразовывают объект в строку и обратно, к сожалению.

Вот код для XML от Acsent:
Преобразование объекта в XML:
    ЗаписьXML = Новый ЗаписьXML;
    ЗаписатьXML(ЗаписьXML, Документ.ПолучитьОбъект());
    
    Стр = ЗаписьXML.Закрыть();
   
   
Преобразование из XML в объект:
    ЧтениеXML = Новый ЧтениеXML;
    ЧтениеXML.УстаноитьСтроку(Стр);
    
    Объект = ПрочитатьXML(ЧтениеXML);


Итак, наиболее простым способом передачи объекта на запись признана XML-серилизация.
Закладка

Описание | Рубрикатор | Поиск | ТелепатБот | Захваченные статьи | Установки | Форум
© Станислав Митичкин (Волшебник), 2005-2021 | Mista.ru

Яндекс.Метрика