Под каким пользователем работает код 1С и можно ли его подменить
Содержание
Сменить текущего пользователя внутри уже открытого сеанса 1С нельзя: платформа фиксирует его при входе в базу. Получить текущего пользователя можно тремя способами: ИмяПользователя() вернёт строку, ПользователиИнформационнойБазы.ТекущийПользователь() вернёт объект пользователя ИБ, а в конфигурациях на БСП Пользователи.ТекущийПользователь() вернёт ссылку на элемент справочника «Пользователи».
Если же задача — «установить» пользователя, то есть выполнить код от другого имени, решения такие: перезапуск с параметрами /N и /P, внешнее соединение с логином и паролем, регламентное задание с заданным пользователем или привилегированный режим, который снимает проверку прав, но имя не меняет. Всё это относится к платформе 8.3 целиком и не зависит от конфигурации, кроме мест, где упомянута БСП.
Что платформа считает текущим пользователем
Текущий пользователь — это учётная запись из списка пользователей информационной базы, под которой открыт сеанс. Её выбирают в окне входа, передают в командной строке или подставляют автоматически через аутентификацию Windows.
От этой учётной записи зависят:
- 🔐 набор ролей и, значит, права на объекты;
- 📋 ограничения на уровне записей (RLS), если они настроены;
- 🧾 поле «Пользователь» в журнале регистрации;
- 🖥️ основной интерфейс, язык и настройки форм.
Если в базе нет ни одного пользователя, окно входа не появляется. Тогда текущий пользователь существует, но у него пустое имя, и ИмяПользователя() вернёт пустую строку. Код, который полагается на имя, в такой базе ломается первым.
В типовых конфигурациях (БП 3.0, ЗУП 3.1, УТ 11, ERP) поверх платформенного пользователя есть второй слой — справочник «Пользователи» из Библиотеки стандартных подсистем. Элемент справочника связан с пользователем ИБ через реквизит ИдентификаторПользователяИБ. Отсюда путаница: «пользователь» в коде может означать два разных объекта.
Как получить текущего пользователя и прочитать его свойства
Имя строкой: ИмяПользователя() и ПолноеИмяПользователя()
Две глобальные функции работают в любом контексте, включая тонкий клиент:
Имя = ИмяПользователя(); // "Иванова" — имя для входа
Полное = ПолноеИмяПользователя(); // "Иванова Мария Петровна"
Этого достаточно для подписи в шапке формы или для сообщения пользователю. Для ссылок и сравнений строка не годится — об этом ниже.
Объект пользователя ИБ
ПользователиИнформационнойБазы.ТекущийПользователь() возвращает объект типа ПользовательИнформационнойБазы. Менеджер ПользователиИнформационнойБазы доступен на сервере, во внешнем соединении и в толстом клиенте. В тонком клиенте его нет, поэтому код выносят в серверную процедуру:
&НаСервереБезКонтекста
Функция ОписаниеТекущегоПользователя()
ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
Описание = Новый Структура;
Описание.Вставить("Имя", ПользовательИБ.Имя);
Описание.Вставить("ПолноеИмя", ПользовательИБ.ПолноеИмя);
Описание.Вставить("Идентификатор", ПользовательИБ.УникальныйИдентификатор);
Описание.Вставить("ВходПоПаролю", ПользовательИБ.АутентификацияСтандартная);
Описание.Вставить("ВходЧерезWindows", ПользовательИБ.АутентификацияОС);
СписокРолей = Новый Массив;
Для Каждого Роль Из ПользовательИБ.Роли Цикл
СписокРолей.Добавить(Роль.Имя);
КонецЦикла;
Описание.Вставить("Роли", СписокРолей);
Возврат Описание;
КонецФункции
Чтение своей собственной записи не требует особых прав. А вот перебор чужих пользователей через ПолучитьПользователей() или НайтиПоИмени() требует права «Администрирование» либо привилегированного режима.
Ссылка на справочник «Пользователи» (БСП)
В конфигурациях на БСП для учётных задач нужен не объект ИБ, а ссылка:
// Общий модуль Пользователи, вызов на сервере
ТекущийПользователь = Пользователи.ТекущийПользователь();
Документ.Ответственный = ТекущийПользователь;
Если в базу заходят внешние пользователи (покупатели, поставщики через личный кабинет), Пользователи.ТекущийПользователь() для них вызывает исключение. Универсальный вариант — Пользователи.АвторизованныйПользователь(): он вернёт ссылку либо на «Пользователи», либо на «Внешние пользователи».
Сведения о сеансе
Иногда нужно знать не только кто, но и откуда зашёл. Для этого есть объект сеанса:
Сеанс = ПолучитьТекущийСеансИнформационнойБазы();
Сообщить(СтрШаблон("%1, сеанс %2, компьютер %3, приложение %4",
Сеанс.Пользователь.Имя,
Формат(Сеанс.НомерСеанса, "ЧГ=0"),
Сеанс.ИмяКомпьютера,
Сеанс.ИмяПриложения));
Функция серверная. Номер сеанса выводим через Формат, чтобы в числе не появились пробелы-разделители разрядов.
Как выполнить код от имени другого пользователя
Подменить пользователя «на лету» платформа не даёт: свойство «текущий» только для чтения, отдельного метода смены нет. Все рабочие способы сводятся к одному — открыть новый сеанс под нужной учётной записью.
| Способ | Когда подходит | Что учесть |
|---|---|---|
Перезапуск с /N и /P | Пользователь сам переключается на другую учётку | Текущий сеанс закрывается |
| Внешнее соединение (COM) | Обработка-робот, интеграция, выгрузка | Только Windows, пароль не храните в коде |
| Регламентное задание | Ночные загрузки, рассылки | Пользователь задаётся в свойствах задания |
| Фоновое задание | Долгая операция без зависания формы | Выполняется от того же пользователя, что и запустил |
| Привилегированный режим | Нужно действие сверх прав, но от того же имени | Имя и RLS-параметры не меняются |
Перезапуск под другим именем
Из клиентского кода сеанс можно завершить и сразу открыть заново с дополнительными параметрами командной строки:
&НаКлиенте
Процедура ВойтиПодДругимИменем(Команда)
ЗавершитьРаботуСистемы(Ложь, Истина, "/N""Склад"" /WA-");
КонецПроцедуры
Параметр /WA- отключает вход через Windows, иначе платформа может снова подставить доменную учётку. Пароль лучше не передавать: окно входа спросит его само.
Тот же приём работает из ярлыка:
"C:\Program Files\1cv8\common\1cestart.exe" ENTERPRISE /F"D:\Bases\Trade" /N"Склад" /WA-
Внешнее соединение
Обработка в одной базе открывает соединение с другой (или с той же) под служебным пользователем:
Коннектор = Новый COMОбъект("V83.COMConnector");
СтрокаСоединения = "Srvr=""srv1c"";Ref=""trade"";Usr=""Робот"";Pwd=""" + ПарольРобота + """";
Соединение = Коннектор.Connect(СтрокаСоединения);
Сообщить(Соединение.ИмяПользователя());
Для файловой базы вместо Srvr и Ref указывают File=""D:\Bases\Trade"". ПарольРобота берите из защищённого хранилища или параметров запуска, а не из текста модуля: модуль видит любой, кто откроет Конфигуратор.
Регламентное задание с заданным пользователем
Пользователя для регламентного задания можно установить программно:
Задание = РегламентныеЗадания.НайтиПредопределенное(Метаданные.РегламентныеЗадания.ЗагрузкаКурсовВалют);
Задание.ИмяПользователя = "Робот";
Задание.Записать();
Имя объекта метаданных здесь условное — подставьте своё. Если ИмяПользователя пустое, задание выполняется от имени пользователя без имени, а при наличии списка пользователей это часто заканчивается ошибкой входа или нехваткой прав.
Привилегированный режим
Когда задача не «стать другим», а «сделать то, на что нет прав», нужен привилегированный режим:
УстановитьПривилегированныйРежим(Истина);
Попытка
// запись в регистр, на который у оператора нет прав
Набор.Записать();
Исключение
УстановитьПривилегированныйРежим(Ложь);
ВызватьИсключение;
КонецПопытки;
УстановитьПривилегированныйРежим(Ложь);
Работает только на сервере. ИмяПользователя() внутри вернёт того же человека, в журнал регистрации тоже попадёт он. Проверить, включён ли режим, можно функцией ПривилегированныйРежим().
Ещё один способ — флаг «Привилегированный» в свойствах общего модуля. Все процедуры такого модуля выполняются без проверки прав. Удобно, но держите в нём только узкие функции, а не всё подряд.
Безопасный режим: что в нём нельзя
Безопасный режим включают, когда исполняют код из ненадёжного источника: внешнюю обработку , текст из реквизита, формулу пользователя.
УстановитьБезопасныйРежим(Истина);
Выполнить(ТекстФормулы);
В безопасном режиме:
- 🚫 включить привилегированный режим нельзя;
- 🚫 запрещены COM-объекты, внешние компоненты и работа с файлами на сервере;
- 🚫 нельзя запустить внешнее приложение.
Отсюда практический вывод: ни перезапуск под другим именем, ни внешнее соединение, ни повышение прав из безопасного режима не сработают. Проверить состояние помогает функция БезопасныйРежим().
Код, который выполняется в безопасном режиме, не может его снять: вызов УстановитьБезопасныйРежим(Ложь) для режима, включённого уровнем выше, вызывает исключение. Сам режим снимается при выходе из процедуры, где его включили. Так задумано, чтобы чужой код не отключил ограничение.
В БСП внешние обработки дополнительно проходят через профили безопасности кластера. Если профиль не разрешает, например, доступ к каталогу, никакие права пользователя этого не исправят.
Строка или ссылка: почему важен тип
Самая частая ошибка — хранить пользователя строкой:
Документ.Автор = ИмяПользователя(); // плохо
Что с этим не так:
- ✏️ администратор переименовал «Иванова» в «Петрова» после замужества — старые документы потеряли связь;
- 👥 два сотрудника с одинаковым полным именем в отчёте сливаются в одну строку;
- 🔍 отбор по строке работает медленнее и чувствителен к регистру и пробелам.
| Что получаем | Тип | Для чего |
|---|---|---|
ИмяПользователя() | Строка | Вывод на экран, сообщения |
ПользователиИнформационнойБазы.ТекущийПользователь() | ПользовательИнформационнойБазы | Роли, способ входа, администрирование |
.УникальныйИдентификатор | УникальныйИдентификатор | Связь со справочником, поиск |
Пользователи.ТекущийПользователь() (БСП) | СправочникСсылка.Пользователи | Реквизиты документов, отборы, отчёты |
Перейти от объекта ИБ к справочнику и обратно можно через идентификатор:
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(
Ссылка.ИдентификаторПользователяИБ);
Если ПользовательИБ = Неопределено Тогда
// у элемента справочника нет учётной записи для входа
КонецЕсли;
Сравнивать строку со ссылкой бессмысленно: условие ИмяПользователя() = Документ.Ответственный всегда ложно, ошибки при этом не будет.
Создание пользователя и выдача ролей из кода
Иногда «установить пользователя» значит завести его программно. На голой платформе это делается так:
НовыйПользователь = ПользователиИнформационнойБазы.СоздатьПользователя();
НовыйПользователь.Имя = "Робот";
НовыйПользователь.ПолноеИмя = "Служебный пользователь для обменов";
НовыйПользователь.Пароль = ПарольРобота;
НовыйПользователь.АутентификацияСтандартная = Истина;
НовыйПользователь.ПоказыватьВСпискеВыбора = Ложь;
НовыйПользователь.Роли.Добавить(Метаданные.Роли.ПолныеПрава);
НовыйПользователь.Записать();
Нужно право «Администрирование». Имя роли ПолныеПрава есть в типовых конфигурациях; в своей подставьте нужную.
В конфигурациях на БСП не создавайте пользователей ИБ напрямую. Справочник «Пользователи» о такой учётке не узнает, группы доступа не применятся, и человек либо не увидит данных, либо увидит лишнее. Заводите элемент справочника, а учётную запись для входа создавайте через его карточку или механизмы самой БСП.
Права в типовых конфигурациях выдают не ролями напрямую, а группами доступа: Администрирование → Настройки пользователей и прав. Добавление роли кодом в обход групп при следующей обработке прав может быть отменено.
Как отследить, кто и что сделал
Журнал регистрации сам записывает пользователя в каждое событие: вход, запись объекта, ошибку. Свои события добавляют так:
ЗаписьЖурналаРегистрации("Обмен.Загрузка",
УровеньЖурналаРегистрации.Информация,
Метаданные.Документы.РеализацияТоваровУслуг,
Документ.Ссылка,
СтрШаблон("Загружено строк: %1", Формат(КоличествоСтрок, "ЧГ=0")));
Пользователь в записи будет тем, под кем идёт сеанс. Поэтому регламентному заданию и обменам стоит дать отдельную учётку вроде «Робот»: в журнале сразу видно, что документ поменял не человек.
Что помогает при разборе:
- 📌 фильтр журнала по пользователю и по событию «Данные. Изменение»;
- 📌 собственные имена событий с префиксом подсистемы, чтобы их легко найти;
- 📌 в БСП — подсистема версионирования объектов: она хранит, кто и какие реквизиты изменил.
Привилегированный режим авторства не скрывает. Если под «Ивановой» запись прошла в обход прав, в журнале всё равно будет «Иванова».
Ошибки при работе с текущим пользователем
Ещё одна тихая ошибка — сохранять результат ИмяПользователя() в переменной модуля приложения и потом использовать её после перезапуска с другим именем. Получайте пользователя в момент, когда он нужен, а не один раз при старте.
Частые вопросы
Можно ли в 1С программно войти под другим пользователем без пароля?
Как узнать, что текущий пользователь — администратор?
ПравоДоступа("Администрирование", Метаданные). В конфигурациях на БСП короче: Пользователи.ЭтоПолноправныйПользователь().Под каким пользователем выполняется фоновое задание?
Можно ли поменять параметр сеанса ТекущийПользователь в БСП?
Чем ИмяПользователя() отличается от ПользовательОС?
ИмяПользователя() — имя учётки в базе 1С. Свойство ПользовательОС у пользователя ИБ — доменная учётка Windows вида \\DOMAIN\ivanova, к которой привязан вход без пароля.