Приветствуем вас, уважаемые коллеги! Сегодня мы детально разберем одну крайне интересную и неочевидную проблему, с которой часто сталкиваются разработчики и администраторы систем на платформе 1С:Предприятие 8.3. Представьте ситуацию: у пользователя при попытке открыть или сформировать отчет на системе компоновки данных (СКД) внезапно возникает критическая ошибка «Нарушение прав доступа!». При этом ни в подробных сведениях об ошибке, ни в стандартном Журнале регистрации никакой детальной технической информации нет. Ситуация осложняется тем, что на 32-разрядном клиенте отчет работает без каких-либо нареканий, а вот на 64-разрядной платформе стабильно выдает ошибку.
Давайте вместе проанализируем эту ситуацию, выясним глубинную причину такого поведения платформы и подробно рассмотрим четыре практических способа решения этой проблемы без предоставления пользователю избыточных прав.
Для начала давайте разберем по шагам, что происходит в системе, когда пользователь запускает отчет на СКД:
ХранилищеСистемныхНастроек или ХранилищеПользовательскихНастроекОтчетов.AppData) для сохранения состояния окон и настроек, при этом игнорируя или мягко обходя ошибки отсутствия прав в базе данных. В современных 64-разрядных клиентах оптимизирован механизм взаимодействия с сервером: вызовы оптимизированы, а проверка прав роли на сервере выполняется максимально строго и бескомпромиссно, что и приводит к гарантированному падению сессии с ошибкой доступа.Конечно, самым простым решением кажется простое включение права «Сохранение данных пользователя» в роли. Однако это дает пользователю нежелательную возможность самостоятельно настраивать панель разделов и панель навигации всей системы, чего администраторы во многих компаниях стараются жестко избегать. Рассмотрим, как решить проблему красиво и профессионально.
Этот метод считается наиболее правильным и архитектурно чистым. Мы перенаправим стандартный механизм сохранения настроек отчета в наше собственное хранилище настроек, которое будет работать в обход ограничений роли пользователя с помощью привилегированного режима.
Рассмотрим по шагам реализацию этого способа:
ПривилегированноеХранилищеНастроек.ПривилегированноеХранилищеНастроек.Посмотрим на пример кода модуля менеджера хранилища настроек. В данном случае мы будем записывать настройки в специально созданный для этого регистр сведений РегистрСведений.СохраненныеНастройкиОтчетов:
Процедура Сохранить(КлючОбъекта, КлючНастроек, Настройки, ОписаниеНастроек, ИмяПользователя) Экспорт
УстановитьПривилегированныйРежим(Истина);
МенеджерЗаписи = РегистрыСведений.СохраненныеНастройкиОтчетов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Пользователь = ИмяПользователя;
МенеджерЗаписи.КлючОбъекта = КлючОбъекта;
МенеджерЗаписи.КлючНастроек = КлючНастроек;
МенеджерЗаписи.Настройки = Новый ХранилищеЗначения(Настройки);
МенеджерЗаписи.ОписаниеНастроек = ОписаниеНастроек;
Попытка
МенеджерЗаписи.Записать();
Исключение
ЗаписатьЛогОшибки("Ошибка сохранения настроек: " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));
КонецПопытки;
КонецПроцедуры
Функция Загрузить(КлючОбъекта, КлючНастроек, ОписаниеНастроек, ИмяПользователя) Экспорт
УстановитьПривилегированныйРежим(Истина);
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СохраненныеНастройкиОтчетов.Настройки КАК Настройки,
| СохраненныеНастройкиОтчетов.ОписаниеНастроек КАК ОписаниеНастроек
|ИЗ
| РегистрСведений.СохраненныеНастройкиОтчетов КАК СохраненныеНастройкиОтчетов
|ГДЕ
| СохраненныеНастройкиОтчетов.Пользователь = &Пользователь
| И СохраненныеНастройкиОтчетов.КлючОбъекта = &КлючОбъекта
| И СохраненныеНастройкиОтчетов.КлючНастроек = &КлючНастроек";
Запрос.УстановитьПараметр("Пользователь", ИмяПользователя);
Запрос.УстановитьПараметр("КлючОбъекта", КлючОбъекта);
Запрос.УстановитьПараметр("КлючНастроек", КлючНастроек);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
ОписаниеНастроек = Выборка.ОписаниеНастроек;
Возврат Выборка.Настройки.Получить();
КонецЕсли;
Возврат Неопределено;
КонецФункции
Благодаря вызову метода УстановитьПривилегированныйРежим(Истина), чтение и запись настроек отчета будут осуществляться под полными правами системы, что полностью нивелирует отсутствие права «Сохранение данных пользователя» у конкретной учетной записи.
Если для данного отчета сохранение вариантов и настроек пользователями вообще не требуется (например, это фиксированный сервисный или административный отчет), мы можем легко отключить саму попытку платформы записать что-либо в хранилище системных настроек.
Разберем по шагам, как это реализовать:
AutoSaveDataInSettings).После этого платформа перестанет автоматически вызывать транзакции сохранения данных при открытии или закрытии этой формы. Ошибка «Нарушение прав доступа!» гарантированно исчезнет, при этом вам даже не придется писать программный код.
Этот способ является гибридным. Мы отключаем автоматическое сохранение настроек формой (как в Способе 2), чтобы избежать системной ошибки ядра, но при этом реализуем загрузку и сохранение параметров вручную через программный код в привилегированном режиме.
Сначала мы отключаем свойство Автоматическое сохранение данных в настройках в свойствах формы. Затем переходим в модуль созданной управляемой формы отчета и пишем следующий код:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Включаем привилегированный режим для обхода ограничений роли
УстановитьПривилегированныйРежим(Истина);
ИмяОтчета = РеквизитФормыВЗначение("Отчет").Метаданные().Имя;
КлючОбъекта = "Отчет." + ИмяОтчета;
КлючНастроек = "ПользовательскиеНастройкиОтчета";
// Загружаем настройки из стандартного ХранилищаОбщихНастроек под привилегированным режимом
НастройкиПользователя = ХранилищеОбщихНастроек.Загрузить(КлючОбъекта, КлючНастроек, , ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
Если НастройкиПользователя <> Неопределено Тогда
Отчет.КомпоновщикНастроек.ЗагрузитьНастройки(НастройкиПользователя);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
Если Не ЗавершениеРаботы Тогда
СохранитьНастройкиНаСервере();
КонецЕсли;
КонецПроцедуры
&НаСервере
Процедура СохранитьНастройкиНаСервере()
УстановитьПривилегированныйРежим(Истина);
ИмяОтчета = РеквизитФормыВЗначение("Отчет").Метаданные().Имя;
КлючОбъекта = "Отчет." + ИмяОтчета;
КлючНастроек = "ПользовательскиеНастройкиОтчета";
// Получаем текущие настройки компоновщика
ТекущиеНастройки = Отчет.КомпоновщикНастроек.ПолучитьНастройки();
// Сохраняем настройки под полными правами
ХранилищеОбщихНастроек.Сохранить(КлючОбъекта, КлючНастроек, ТекущиеНастройки, , ПользователиИнформационнойБазы.ТекущийПользователь().Имя);
КонецПроцедуры
Этот способ удобен тем, что нам не требуется создавать новые объекты метаданных (новые Хранилища настроек) в дереве конфигурации. Мы продолжаем использовать системное ХранилищеОбщихНастроек, но делаем это контролируемо и безопасно.
Если ваша конфигурация разработана на основе БСП (а это практически все типовые решения от фирмы 1С: ERP, Управление торговлей, Комплексная автоматизация, Бухгалтерия предприятия и др.), вы можете задействовать штатный механизм интеграции дополнительных отчетов и обработок.
Проанализируем этот вариант подробнее:
.erf).Механизмы БСП спроектированы таким образом, что запуск дополнительных отчетов происходит внутри специального безопасного программного контейнера. БСП берет на себя всю работу по сохранению вариантов отчетов и пользовательских настроек в свои собственные регистры сведений (такие как РегистрСведений.ВариантыОтчетов). Все эти операции БСП по умолчанию выполняет в привилегированном режиме, поэтому у рядового пользователя никогда не возникнет ошибки нехватки прав доступа, даже если роль «Сохранение данных пользователя» у него полностью отключена.
Мы рассмотрели технические аспекты поведения платформы 1С:Предприятие 8.3 при формировании отчетов на СКД в 64-разрядных средах. Для исправления ошибки «Нарушение прав доступа!» без выдачи избыточных прав на интерфейс мы рекомендуем использовать Способ 1 (если отчет встроен в конфигурацию и критически важно сохранять индивидуальные настройки пользователей) или Способ 2 (если сохранение настроек отчета пользователю не требуется).