Текущий пользователь в клиентском коде 1С 8.3: имя, UUID и ссылка на справочник
Содержание
Чтобы получить пользователя на клиенте 1С, вызовите глобальную функцию ИмяПользователя(): она работает в процедурах с директивой &НаКлиенте, в тонком и веб-клиенте, без обращения к серверу. Полное имя возвращает ПолноеИмяПользователя(). Всё остальное (UUID, роли, ссылку на элемент справочника) придётся брать через сервер или из параметров клиента.
Типичная ситуация: разработчик дописывает в форму документа кнопку «Взять в работу» и хочет сразу подставить в поле ответственного текущего сотрудника. Пишет в клиентском обработчике ПользователиИнформационнойБазы.ТекущийПользователь() и получает ошибку компиляции. Разберём, что доступно на клиенте, что нет и как сделать правильно, чтобы не гонять лишние серверные вызовы.
Где выполняется код: клиент, сервер и почему это важно
В управляемом приложении модуль формы делится на части, и каждая выполняется в своём месте. Директива перед процедурой определяет, какие объекты платформы ей доступны.
| Директива | Где выполняется | Доступ к данным формы | Доступ к базе |
|---|---|---|---|
&НаКлиенте | на компьютере пользователя или в браузере | да | нет |
&НаСервере | на сервере 1С | да, форма передаётся на сервер | да |
&НаСервереБезКонтекста | на сервере 1С | нет | да |
&НаКлиентеНаСервереБезКонтекста | там, откуда вызвали | нет | только если вызвали на сервере |
Из этого вытекает главное правило темы:
- 🖥️ на клиенте доступны функции глобального контекста, которые платформа помечает как клиентские, — среди них
ИмяПользователя()иПолноеИмяПользователя(); - 🗄️ менеджер
ПользователиИнформационнойБазы, параметры сеанса, запросы и чтение справочников живут на сервере; - 🔁 каждый переход клиент → сервер — это вызов по сети. В веб-клиенте и при работе через интернет он заметно дороже, чем в локальной сети.
Директива &НаСервереБезКонтекста для получения данных о пользователе почти всегда лучше, чем &НаСервере: на сервер не уходят реквизиты формы, вызов легче.
ИмяПользователя() и ПолноеИмяПользователя(): ответ без вызова сервера
Две функции глобального контекста закрывают большую часть задач, где нужен только текст: подпись в комментарии, приветствие, строка в журнал.
&НаКлиенте
Процедура ВзятьВРаботу(Команда)
Имя = ИмяПользователя(); // имя для входа, например "ivanova"
Представление = ПолноеИмяПользователя(); // "Иванова Мария Петровна"
Объект.Комментарий = СтрШаблон("Взято в работу: %1", Представление);
КонецПроцедуры
Чем отличаются функции:
| Функция | Что возвращает | Где задаётся |
|---|---|---|
ИмяПользователя() | свойство «Имя» пользователя ИБ — то, что вводят в окне входа | Конфигуратор: Администрирование → Пользователи, поле «Имя» |
ПолноеИмяПользователя() | свойство «Полное имя» | там же, поле «Полное имя» |
Обе функции возвращают строку. Если список пользователей базы пуст, строка тоже пустая — об этом подробно ниже.
Имя пользователя ИБ можно переименовать. Если вы сохраняете его в реквизит документа, через год там может оказаться имя, которого в базе уже нет. Для связи с данными храните ссылку на элемент справочника или UUID.
ПользователиИнформационнойБазы на клиенте: почему не работает и как обойти
В тонком и веб-клиенте менеджер ПользователиИнформационнойБазы недоступен. Код вида:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ТекущийПользователь = ПользователиИнформационнойБазы.ТекущийПользователь(); // ошибка
КонецПроцедуры
не пройдёт проверку модуля: платформа сообщит Переменная не определена (ПользователиИнформационнойБазы).
Тип ПользовательИнформационнойБазы тоже серверный. Вернуть сам объект на клиент нельзя — передаются только значения, которые умеют сериализоваться: строки, числа, булево, даты, УникальныйИдентификатор, ссылки, структуры и массивы из них.
Рабочая схема — серверная функция, которая собирает нужные свойства в структуру:
&НаСервереБезКонтекста
Функция ДанныеТекущегоПользователя()
ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
Результат = Новый Структура;
Результат.Вставить("Имя", ПользовательИБ.Имя);
Результат.Вставить("ПолноеИмя", ПользовательИБ.ПолноеИмя);
Результат.Вставить("Идентификатор", ПользовательИБ.УникальныйИдентификатор);
Результат.Вставить("ВходПоПаролю", ПользовательИБ.АутентификацияСтандартная);
Результат.Вставить("ВходЧерезОС", ПользовательИБ.АутентификацияОС);
Результат.Вставить("ПользовательОС", ПользовательИБ.ПользовательОС);
Возврат Результат;
КонецФункции
&НаКлиенте
Процедура ПоказатьПользователя(Команда)
Данные = ДанныеТекущегоПользователя();
Сообщить(СтрШаблон("%1 (%2)", Данные.ПолноеИмя, Данные.Имя));
КонецПроцедуры
Собирайте в структуру всё, что понадобится форме, за один вызов. Три отдельные серверные функции для имени, UUID и способа входа — три сетевых обращения вместо одного.
Права на чтение пользователей ИБ
Текущего пользователя через ТекущийПользователь() читает любой, без особых прав. А вот поиск других пользователей (НайтиПоИмени, НайтиПоУникальномуИдентификатору, ПолучитьПользователей) требует права «Администрирование». Если такая функция нужна обычному пользователю, включайте привилегированный режим на сервере и возвращайте на клиент только необходимые поля:
&НаСервереБезКонтекста
Функция ПолноеИмяПоИмени(ИмяДляВхода)
УстановитьПривилегированныйРежим(Истина);
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоИмени(ИмяДляВхода);
Если ПользовательИБ = Неопределено Тогда
Возврат "";
КонецЕсли;
Возврат ПользовательИБ.ПолноеИмя;
КонецФункции
Не возвращайте на клиент списки ролей, признаки входа и прочие сведения о чужих учётных записях без необходимости — привилегированный режим снимает проверку прав, и ответственность за утечку данных лежит на коде.
Как получить UUID пользователя на клиенте
Уникальный идентификатор — самый надёжный ключ пользователя ИБ: он не меняется при переименовании и смене полного имени. На клиенте прямой функции для него нет, поэтому только через сервер.
Минимальный вариант:
&НаСервереБезКонтекста
Функция ИдентификаторТекущегоПользователя()
Возврат ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
КонецФункции
&НаКлиенте
Процедура ПриОткрытии(Отказ)
ИдПользователя = ИдентификаторТекущегоПользователя();
// тип значения — УникальныйИдентификатор, его можно хранить в реквизите формы
КонецПроцедуры
Если UUID нужен часто — в нескольких формах, в обработчиках ожидания, — не вызывайте сервер каждый раз. Вынесите функцию в общий модуль с настройками:
- Создайте общий модуль, например
РаботаСПользователямиПовтИсп. - Установите флажки «Сервер» и «Вызов сервера».
- В свойстве «Повторное использование возвращаемых значений» выберите «На время сеанса».
- Поместите в модуль экспортную функцию, которая возвращает UUID или структуру с данными пользователя.
// Общий модуль РаботаСПользователямиПовтИсп (Сервер, Вызов сервера, На время сеанса)
Функция ИдентификаторТекущегоПользователя() Экспорт
Возврат ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
КонецФункции
Первый вызов уйдёт на сервер, повторные в том же сеансе вернут сохранённое значение. Для данных о текущем пользователе это безопасно: они не меняются, пока сеанс жив.
Строковое представление UUID получают через Строка(Идентификатор), обратное преобразование — Новый УникальныйИдентификатор(Строка). Удобно для записи в журнал или передачи во внешнюю систему.
Пользователь в типовых конфигурациях на БСП
В Бухгалтерии 3.0, ЗУП 3.1, УТ 11 и других конфигурациях на Библиотеке стандартных подсистем пользователь ИБ — это только учётная запись для входа. В данных (поле «Ответственный», «Автор», «Менеджер») хранится ссылка на элемент справочника «Пользователи». Связь между ними — реквизит справочника ИдентификаторПользователяИБ.
Для клиентского кода в БСП есть готовая функция, которая не делает серверного вызова:
&НаКлиенте
Процедура ЗаполнитьОтветственного(Команда)
Объект.Ответственный = ПользователиКлиент.ТекущийПользователь();
КонецПроцедуры
Ссылка на текущего пользователя загружается в параметры клиента при запуске программы, поэтому функция отрабатывает мгновенно. На сервере то же самое делает Пользователи.ТекущийПользователь().
Что выбрать в типовой базе:
| Задача | Чем пользоваться |
|---|---|
| заполнить реквизит «Ответственный» на клиенте | ПользователиКлиент.ТекущийПользователь() |
| то же в серверной процедуре | Пользователи.ТекущийПользователь() |
| сеанс может быть у внешнего пользователя (портал, личный кабинет) | ПользователиКлиент.АвторизованныйПользователь() |
| нужна строка для вывода | ПолноеИмяПользователя() |
В сеансе внешнего пользователя функция ТекущийПользователь() вызывает исключение: такого элемента в справочнике «Пользователи» нет, он лежит в справочнике «Внешние пользователи». Если форма открывается и внешними пользователями, работайте через АвторизованныйПользователь() и проверяйте тип ссылки.
В старых редакциях БСП клиентская функция находилась в модуле ПользователиКлиентСервер. Если код из старой обработки не компилируется на новой конфигурации, проверьте, в каком модуле функция объявлена сейчас, — найдите её через поиск по конфигурации (Ctrl+Shift+F в конфигураторе).
Если в конфигурации нет БСП
В самописных и старых базах справочника «Пользователи» с привязкой к учётной записи может не быть. Тогда связь делают сами: заводят в своём справочнике (например, «Сотрудники») реквизит ИдентификаторПользователяИБ с типом УникальныйИдентификатор и ищут по нему.
// Общий модуль СотрудникиПовтИсп (Сервер, Вызов сервера, На время сеанса)
Функция ТекущийСотрудник() Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| Сотрудники.Ссылка КАК Ссылка
|ИЗ
| Справочник.Сотрудники КАК Сотрудники
|ГДЕ
| Сотрудники.ИдентификаторПользователяИБ = &Идентификатор";
Запрос.УстановитьПараметр("Идентификатор",
ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка;
КонецЕсли;
Возврат Справочники.Сотрудники.ПустаяСсылка();
КонецФункции
На клиенте вызов выглядит так: Объект.Ответственный = СотрудникиПовтИсп.ТекущийСотрудник();. Ссылка вернётся одна на весь сеанс, повторных запросов к базе не будет.
Почему связь по UUID, а не по имени: имя для входа администратор может поменять, например после смены фамилии сотрудника. Привязка по строке тогда тихо отвалится, а по идентификатору — сохранится.
Пустую ссылку на клиенте проверяйте через ЗначениеЗаполнено(): если сотрудник не привязан к учётной записи, покажите сообщение, а не записывайте документ с пустым ответственным.
Не дописывайте свои функции в типовые общие модули: при обновлении конфигурации правки придётся переносить вручную. Своё размещайте в отдельных модулях или в расширении.
Тонкий клиент, веб-клиент и толстый клиент: в чём разница
ИмяПользователя() и ПолноеИмяПользователя() ведут себя одинаково во всех клиентах. Различия начинаются, когда нужно что-то кроме них.
| Клиент | ПользователиИнформационнойБазы на клиенте | Что учесть |
|---|---|---|
| тонкий клиент | недоступен | данные — через серверный вызов или параметры клиента |
| веб-клиент | недоступен | каждый серверный вызов — HTTP-запрос, кэширование особенно важно |
| толстый клиент, обычное приложение | доступен прямо в клиентском коде | код не переносится в управляемые формы без переделки |
| толстый клиент, управляемое приложение | в модулях управляемых форм — как в тонком | директивы компиляции обязательны |
Имя пользователя Windows
Частый смежный вопрос — как узнать учётную запись Windows, под которой человек сидит за компьютером.
- 🔐 Если у пользователя ИБ включена аутентификация операционной системы, свойство
ПользовательОСна сервере вернёт строку вида\\DOMAIN\ivanova. Это самый надёжный путь, он работает и в веб-клиенте. - 🪟 В тонком клиенте под Windows можно прочитать имя через COM-объект
WScript.Network. Способ не работает в веб-клиенте, на Linux и macOS.
&НаКлиенте
Функция ИмяПользователяWindows()
#Если ВебКлиент Тогда
Возврат "";
#Иначе
Попытка
Сеть = Новый COMОбъект("WScript.Network");
Возврат Сеть.UserName;
Исключение
Возврат "";
КонецПопытки;
#КонецЕсли
КонецФункции
Рядом пригодится ИмяКомпьютера() — функция доступна на клиенте и возвращает имя машины, где запущен клиент. Вместе с ИмяПользователя() её пишут в журналы собственных событий.
Пустой список пользователей и другие ошибки
Если в конфигураторе в списке пользователей нет ни одной записи, база запускается без окна входа. В таком режиме:
- 👤
ИмяПользователя()иПолноеИмяПользователя()возвращают пустую строку; - 🔑 сеанс работает со всеми правами;
- 📭 найти «текущего» пользователя в списке через
НайтиПоИменине получится — искать нечего.
Поэтому любой код, который опирается на имя, должен проверять пустоту:
&НаКлиенте
Процедура ПроверитьПользователя()
Если ПустаяСтрока(ИмяПользователя()) Тогда
ПоказатьПредупреждение(, "В базе не заведены пользователи. Действие недоступно.");
Возврат;
КонецЕсли;
// дальнейшая логика
КонецПроцедуры
Проверяйте именно имя, а не UUID: сравнивать идентификатор «пустого» пользователя с чем-то бессмысленно, а ветка с пустым именем читается сразу.
В типовых конфигурациях на БСП при пустом списке пользователей при первом входе обычно создаётся служебная запись, и ПользователиКлиент.ТекущийПользователь() вернёт её ссылку. Не рассчитывайте, что ссылка будет пустой.
Частые вопросы
Можно ли получить пользователя в фоновом задании?
ИмяПользователя() и ПользователиИнформационнойБазы.ТекущийПользователь() вернут его. Регламентное задание работает от пользователя, указанного в его настройках.Как узнать, что пользователь — администратор, не вызывая сервер?
Чем ИмяПользователя() отличается от ссылки на справочник «Пользователи»?
Почему вызов с директивой &НаСервере тормозит форму?
&НаСервереБезКонтекста.Можно ли сменить пользователя без перезапуска программы?
ЗавершитьРаботуСистемы(Ложь, Истина) — второй параметр отвечает за повторный запуск.