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