В типовых конфигурациях фирмы «1С» (таких как ЗУП, БП, ERP или УТ) за создание и управление пользователями отвечает Библиотека стандартных подсистем (БСП). Интерфейсно этот процесс выглядит просто: администратор заходит в специальный справочник в режиме «1С:Предприятие» и создает карточку сотрудника. Однако на уровне платформы «1С:Предприятие 8.3» встроенного готового интерфейса для этого нет. Вся магия происходит программно. Для технического обслуживания таких систем удобно использовать автоматическое архивирование, обновление и тестирование информационных баз в тихом режиме.
Если мы разрабатываем собственную конфигурацию «с нуля» или дорабатываем существующую систему без БСП, нам придется самостоятельно написать логику связывания элементов справочника и учетных записей информационной базы (ИБ). В этой статье мы подробно разберем, как реализовать этот механизм, исправим популярные синтаксические ошибки при работе с коллекциями ролей и рассмотрим архитектурные лучшие практики.
Для начала проанализируем ключевое архитектурное разделение в системе «1С:Предприятие». Существуют две сущности, которые часто путают начинающие разработчики:
ПользователиИнформационнойБазы.Наша главная задача при создании пользователя в режиме «1С:Предприятие» — синхронизировать эти два объекта. При записи элемента справочника система должна автоматически создавать или обновлять соответствующего пользователя ИБ. Аналогичная логика сопоставления по произвольным полям поиска применяется, когда выполняется перенос данных между похожими конфигурациями 1С при несовпадении внутренних ссылок.
Рассмотрим код, который часто пытаются использовать разработчики при создании пользователя ИБ в обработчике ПередЗаписьюНаСервере или в модуле объекта:
НовыйПользователь = ПользователиИнформационнойБазы.СоздатьПользователя();
НовыйПользователь.Имя = Объект.Имя;
НовыйПользователь.ПолноеИмя = Объект.ПолноеИмя;
НовыйПользователь.АутентификацияСтандартная = Истина;
НовыйПользователь.Пароль = Объект.Пароль;
// Ошибочная строка:
НовыйПользователь.Роли.Добавить(Метаданные.Роли.Объект.Роль);
НовыйПользователь.Записать();
При выполнении этого кода система выдает ошибку: «Поле объекта не обнаружено (Объект)». Выясним причину ее возникновения.
Конструкция Метаданные.Роли возвращает коллекцию описания всех ролей, существующих в конфигурации. Когда мы пишем Метаданные.Роли.Объект.Роль, платформа пытается найти в метаданных роль с именем «Объект», которой, разумеется, не существует. Платформа воспринимает слово «Объект» как имя конкретной роли в конфигураторе, а не как обращение к реквизитам нашей формы справочника.
Способ обращения к метаданным зависит от того, в каком виде хранится информация о роли в вашем справочнике.
Вариант 1: Если реквизит «Роль» является строкой
Если в реквизите справочника Объект.Роль хранится строковое имя роли (точно так же, как она называется в конфигураторе, например, "Администратор" или "Кассир"), то обращаться к коллекции метаданных нужно через квадратные скобки:
ИмяРоли = Объект.Роль; // Строковое значение, например "Администратор"
НайденнаяРоль = Метаданные.Роли[ИмяРоли];
Если НайденнаяРоль <> Неопределено Тогда
НовыйПользователь.Роли.Добавить(НайденнаяРоль);
Иначе
ВызватьИсключение "Указанная роль не найдена в конфигурации!";
КонецЕсли;
Вариант 2: Если реквизит «Роль» является ссылкой (на справочник или перечисление)
Если вы создали специальный справочник «РолиПользователей», чтобы предоставить администратору удобный выбор, то в реквизите справочника будет храниться ссылка. В этом случае у справочника должен быть строковый реквизит (например, ИмяВКонфигурации), куда записывается точное системное имя роли:
ИмяРоли = Объект.Роль.ИмяВКонфигурации; // Получаем строковое имя из ссылки
НайденнаяРоль = Метаданные.Роли.Найти(ИмяРоли);
Если НайденнаяРоль <> Неопределено Тогда
НовыйПользователь.Роли.Добавить(НайденнаяРоль);
КонецЕсли;
Просто создать пользователя ИБ при записи справочника недостаточно. Если мы оставим код в исходном виде, то при каждом последующем изменении элемента справочника (например, при редактировании полного имени) система будет пытаться создать пользователя ИБ заново. Это приведет к ошибке неуникальности имени.
Чтобы этого избежать, мы должны связать элемент справочника и системного пользователя с помощью уникального идентификатора (UUID). Разберем этот процесс по шагам:
ИдентификаторПользователяИБ с типом УникальныйИдентификатор.Если обычный пользователь (например, сотрудник отдела кадров) попытается записать карточку нового сотрудника, платформа вернет ошибку нарушения прав доступа. Дело в том, что работать с объектом ПользователиИнформационнойБазы по умолчанию могут только пользователи с административными правами.
Чтобы решить эту проблему, всю процедуру записи пользователя ИБ необходимо выполнять в привилегированном режиме. Это позволит программе временно отключить проверку прав доступа на время выполнения конкретного блока кода.
Рассмотрим готовый шаблон кода, который необходимо разместить в Модуле объекта справочника «Пользователи» в обработчике события ПередЗаписью. Этот код учитывает все особенности работы с UUID, безопасную перезапись ролей, очистку паролей и привилегированный режим.
Процедура ПередЗаписью(Отказ)
// Исключаем работу кода при обмене данными
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
// Включаем привилегированный режим для работы с пользователями ИБ без прав администратора
УстановитьПривилегированныйРежим(Истина);
ПользовательИБ = Неопределено;
// Шаг 1. Пытаемся найти существующего пользователя ИБ по UUID
Если ЗначениеЗаполнено(ИдентификаторПользователяИБ) Тогда
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(ИдентификаторПользователяИБ);
КонецЕсли;
// Шаг 1.2. Если по UUID не нашли, проверяем по имени (защита от дублирования при переносе базы)
Если ПользовательИБ = Неопределено Тогда
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(Наименование);
КонецЕсли;
// Шаг 1.3. Если пользователя все еще нет — создаем новый объект
Если ПользовательИБ = Неопределено Тогда
ПользовательИБ = ПользователиИнформационнойБазы.СоздатьПользователя();
КонецЕсли;
// Шаг 2. Заполняем основные свойства
ПользовательИБ.Имя = Наименование;
ПользовательИБ.ПолноеИмя = ПолноеИмя; // Реквизит нашего справочника
ПользовательИБ.АутентификацияСтандартная = Истина;
ПользовательИБ.ПоказыватьВСпискеВыбора = Истина;
// Шаг 3. Обработка пароля
// Настоятельно рекомендуем не хранить пароль в открытом виде в справочнике!
// Лучше передавать его через ДополнительныеСвойства формы в момент изменения
Если ДополнительныеСвойства.Свойство("НовыйПароль") Тогда
ПользовательИБ.Пароль = ДополнительныеСвойства.НовыйПароль;
КонецЕсли;
// Шаг 4. Безопасный сброс и установка ролей
ПользовательИБ.Роли.Очистить();
Если ЗначениеЗаполнено(Роль) Тогда
// Проверяем тип реквизита "Роль". Если это ссылка - берем строковое имя
ИмяРолиДляПоиска = ?(ТипЗнч(Роль) = Тип("Строка"), Роль, Роль.ИмяВКонфигурации);
НайденнаяРоль = Метаданные.Роли.Найти(ИмяРолиДляПоиска);
Если НайденнаяРоль <> Неопределено Тогда
ПользовательИБ.Роли.Добавить(НайденнаяРоль);
Иначе
ЗаписатьВЖурналРегистрации("Пользователи", УровеньЖурналаРегистрации.Предупреждение, , ,
"Не удалось найти роль в метаданных: " + ИмяРолиДляПоиска);
КонецЕсли;
КонецЕсли;
// Шаг 5. Запись системного пользователя и сохранение связи
Попытка
ПользовательИБ.Записать();
// Сохраняем полученный UUID в реквизит справочника
ИдентификаторПользователяИБ = ПользовательИБ.УникальныйИдентификатор;
Исключение
Отказ = Истина;
ОбщегоНазначенияКлиентСервер.СообщитьПользователю(
"Не удалось сохранить пользователя информационной базы: " + ОписаниеОшибки()
);
КонецПопытки;
// Отключаем привилегированный режим
УстановитьПривилегированныйРежим(Ложь);
КонецПроцедуры
Разработанная схема гарантирует стабильную синхронизацию системных учетных записей со справочником вашей конфигурации. Программа автоматически создаст пользователя ИБ при первом сохранении карточки сотрудника и обновит его свойства при последующих изменениях, избегая конфликтов уникальности имен и прав доступа.