Текущий пользователь в коде 1С: функции платформы, БСП, запрос, роли и сеанс
Содержание
Самый короткий способ определить пользователя в 1С программно — вызвать ИмяПользователя(): функция глобального контекста возвращает имя, под которым выполнен вход, и работает и на клиенте, и на сервере. Если нужен сам объект пользователя информационной базы, на сервере вызывайте ПользователиИнформационнойБазы.ТекущийПользователь(), а в типовых конфигурациях на БСП — Пользователи.ТекущийПользователь(), который вернёт ссылку на элемент справочника «Пользователи».
Типичная ситуация: бухгалтер просит, чтобы в комментарий документа автоматически подставлялся автор, или чтобы кнопка «Провести задним числом» была видна только главбуху. В обоих случаях код должен знать, кто сейчас работает в базе. Ниже — пять способов, их отличия и места, где каждый из них ломается.
Функции платформы: ИмяПользователя() и ТекущийПользователь()
Платформа 1С:Предприятие 8.3 даёт три базовых инструмента. Конфигурация при этом может быть любой, даже пустой.
| Метод | Что возвращает | Где доступен |
|---|---|---|
ИмяПользователя() | Строка — имя для входа | Клиент и сервер |
ПолноеИмяПользователя() | Строка — полное имя из списка пользователей | Клиент и сервер |
ПользователиИнформационнойБазы.ТекущийПользователь() | Объект ПользовательИнформационнойБазы | Сервер, толстый клиент, внешнее соединение |
Пример для общего модуля или модуля объекта:
Имя = ИмяПользователя(); // "Иванова"
ПолноеИмя = ПолноеИмяПользователя(); // "Иванова Мария Петровна"
ТекПользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
Сообщить("Имя: " + ТекПользователь.Имя);
Сообщить("Полное имя: " + ТекПользователь.ПолноеИмя);
Сообщить("Идентификатор: " + Строка(ТекПользователь.УникальныйИдентификатор));
У объекта ПользовательИнформационнойБазы полезны такие свойства:
- 🔑
ИмяиПолноеИмя— то же, что дают глобальные функции; - 🆔
УникальныйИдентификатор— не меняется при переименовании, по нему надёжно связывать пользователя со справочниками; - 🛡️
Роли— коллекция назначенных ролей; - 💻
АутентификацияОСиПользовательОС— включён ли вход через Windows и под какой учётной записью домена (строка вида\\DOMAIN\ivanova); - 🌐
ЯзыкиОсновнойИнтерфейс— настройки сеанса.
Если в базе нет ни одного пользователя (список в Конфигураторе пуст), ИмяПользователя() вернёт пустую строку. Код, который строит что-то на имени, должен это учитывать.
Имя пользователя — плохой ключ для хранения. Его переименовывают при замужестве, смене логина или наведении порядка. Сохраняйте УникальныйИдентификатор или ссылку на справочник, а имя используйте только для вывода на экран.
Текущий пользователь в типовых конфигурациях на БСП
В Бухгалтерии предприятия 3.0, ЗУП 3.1, УТ 11 и других типовых решениях есть справочник «Пользователи» из Библиотеки стандартных подсистем. Каждый его элемент связан с пользователем информационной базы через реквизит ИдентификаторПользователяИБ.
Именно ссылка на этот справочник пишется в реквизиты «Ответственный», «Автор», «Менеджер». Получать её нужно через программный интерфейс БСП:
// На сервере
ТекущийПользователь = Пользователи.ТекущийПользователь();
// Тип: СправочникСсылка.Пользователи
ЭтоПолноправный = Пользователи.ЭтоПолноправныйПользователь();
// Если в базе возможны внешние пользователи (портал, личный кабинет)
Авторизованный = Пользователи.АвторизованныйПользователь();
// Тип: СправочникСсылка.Пользователи или СправочникСсылка.ВнешниеПользователи
На клиенте есть зеркальный модуль ПользователиКлиент с функциями ТекущийПользователь() и АвторизованныйПользователь(). Они берут значение из параметров, переданных клиенту при старте, и не делают лишнего серверного вызова.
Пользователи.ТекущийПользователь() вызывает исключение, если сеанс открыт внешним пользователем. Там, где возможен вход через портал, используйте АвторизованныйПользователь().
Внутри БСП текущий пользователь хранится в параметре сеанса ПараметрыСеанса.ТекущийПользователь. Читать его напрямую технически можно, но правильнее работать через общий модуль Пользователи: библиотека сама заполняет параметр при первом обращении и обрабатывает служебные случаи.
Когда в базе нет ни одного пользователя ИБ, БСП не возвращает пустую ссылку. Она подставляет служебный элемент справочника, обычно с наименованием «<Не указан>». Для автозаполнения «Ответственного» в демобазе это нормально, для отчётов по авторам — нет.
Запрос к справочнику: подразделение, физлицо, контакты
Одной ссылки часто мало: нужно подразделение, физическое лицо или e-mail. Для разового значения хватит обращения через точку, для нескольких полей и отборов — запроса.
Связка по идентификатору пользователя ИБ работает и без БСП-функций, например в обработке, которая подключается к старой базе:
&НаСервере
Функция ДанныеТекущегоПользователя()
ИдПользователяИБ = ПользователиИнформационнойБазы.ТекущийПользователь().УникальныйИдентификатор;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Пользователи.Ссылка КАК Ссылка,
| Пользователи.Наименование КАК Наименование,
| Пользователи.ФизическоеЛицо КАК ФизическоеЛицо,
| Пользователи.Подразделение КАК Подразделение
|ИЗ
| Справочник.Пользователи КАК Пользователи
|ГДЕ
| Пользователи.ИдентификаторПользователяИБ = &ИдПользователяИБ";
Запрос.УстановитьПараметр("ИдПользователяИБ", ИдПользователяИБ);
Выборка = Запрос.Выполнить().Выбрать();
Если Не Выборка.Следующий() Тогда
Возврат Неопределено;
КонецЕсли;
Результат = Новый Структура("Ссылка, Наименование, ФизическоеЛицо, Подразделение");
ЗаполнитьЗначенияСвойств(Результат, Выборка);
Возврат Результат;
КонецФункции
Если ссылка уже получена через Пользователи.ТекущийПользователь(), отбор делайте по ней: ГДЕ Пользователи.Ссылка = &ТекущийПользователь. Реквизиты ФизическоеЛицо и Подразделение есть в типовых БП и ЗУП. В самописной конфигурации проверьте состав реквизитов справочника в Конфигураторе.
В языке запросов нет встроенной функции «текущий пользователь». Значение всегда передаётся параметром. Исключение — шаблоны ограничения доступа на уровне записей (RLS): там можно сослаться на параметр сеанса, например &ТекущийПользователь.
Ещё один способ быстро взять реквизит без запроса — ОбщегоНазначения.ЗначениеРеквизитаОбъекта(Пользователи.ТекущийПользователь(), "ФизическоеЛицо"). Функция есть в БСП и сама формирует запрос.
Код на клиенте: тонкий клиент, веб-клиент и управляемая форма
Это место, где ломается большинство примеров из интернета. В управляемом приложении глобальное свойство ПользователиИнформационнойБазы на клиенте недоступно. Код вида
&НаКлиенте
Процедура Команда1(Команда)
Пользователь = ПользователиИнформационнойБазы.ТекущийПользователь();
КонецПроцедуры
не пройдёт проверку модуля: тонкий и веб-клиент не знают этой переменной. Доступ к параметрам сеанса на клиенте тоже закрыт.
Что работает на клиенте:
ИмяПользователя()иПолноеИмяПользователя()— без серверного вызова.- В конфигурациях на БСП —
ПользователиКлиент.ТекущийПользователь(). - Во всех остальных случаях — получить значение на сервере и сохранить в реквизит формы.
Третий вариант для формы выглядит так:
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ТекущийПользователь = Пользователи.ТекущийПользователь(); // реквизит формы
КонецПроцедуры
&НаКлиенте
Процедура ЗаполнитьОтветственного(Команда)
Объект.Ответственный = ТекущийПользователь;
КонецПроцедуры
Значение берётся один раз при открытии формы, дальше клиент обращается к реквизиту без лишних запросов к серверу. Если пользователь нужен в процедуре без контекста формы, используйте функцию с директивой &НаСервереБезКонтекста: она не передаёт данные формы на сервер и работает быстрее.
Для веб-клиента правила те же. Разница только в том, что функции, связанные с компьютером клиента, ведут себя иначе: например, ИмяКомпьютера(), вызванная на сервере, вернёт имя сервера 1С, а не рабочего места пользователя.
Проверка ролей и прав пользователя
Чаще всего пользователя определяют не ради имени, а чтобы решить: показывать кнопку или нет, разрешить действие или нет. Для этого не нужно сравнивать имя со списком — проверяйте роли и права.
Проверка роли в текущем сеансе. Функция РольДоступна() доступна и на клиенте, и на сервере:
Если РольДоступна("ПолныеПрава") Тогда
Элементы.ПровестиЗаднимЧислом.Видимость = Истина;
КонецЕсли;
// Вариант с метаданными: опечатку в имени роли заметит проверка модуля
Если РольДоступна(Метаданные.Роли.ПолныеПрава) Тогда
// ...
КонецЕсли;
Проверка права на объект. ПравоДоступа() отвечает на вопрос «может ли пользователь изменить этот документ», независимо от того, какой ролью право выдано:
МожноИзменять = ПравоДоступа("Изменение", Метаданные.Документы.РеализацияТоваровУслуг);
Список ролей конкретного пользователя ИБ — через коллекцию Роли на сервере:
ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
Для Каждого Роль Из ПользовательИБ.Роли Цикл
Сообщить(Роль.Имя);
КонецЦикла;
В БСП для группы ролей есть Пользователи.РолиДоступны("ДобавлениеИзменениеДанныхБанков, ПолныеПрава") — функция вернёт Истина, если доступна хотя бы одна из перечисленных.
| Задача | Метод | Комментарий |
|---|---|---|
| Скрыть элемент для не-администраторов | Пользователи.ЭтоПолноправныйПользователь() | Учитывает и роль администратора системы |
| Разрешить действие по роли | РольДоступна() | Работает в текущем сеансе |
| Проверить право на объект | ПравоДоступа() | Не зависит от имени роли |
| Узнать роли другого пользователя | ПользовательИнформационнойБазы.Роли | Получение чужого пользователя требует административных прав |
Скрытие кнопки на форме — не защита. Если действие критично, проверка прав должна стоять и на сервере, в коде, который это действие выполняет. Иначе ту же операцию можно вызвать из другой формы или обработки.
Сеанс, метаданные и данные о подключении
Иногда нужен не просто пользователь, а контекст его работы: с какого компьютера, каким клиентом, с какого времени. Для этого есть объект СеансИнформационнойБазы.
&НаСервере
Процедура ЗаписатьВЖурналДанныеСеанса()
Сеанс = ПолучитьТекущийСеансИнформационнойБазы();
Текст = СтрШаблон("Пользователь: %1; компьютер: %2; приложение: %3; начало: %4; сеанс №%5",
Сеанс.Пользователь.Имя,
Сеанс.ИмяКомпьютера,
ПредставлениеПриложения(Сеанс.ИмяПриложения),
Сеанс.НачалоСеанса,
Формат(Сеанс.НомерСеанса, "ЧГ=0"));
ЗаписьЖурналаРегистрации("Аудит.ДанныеСеанса", УровеньЖурналаРегистрации.Информация, , , Текст);
КонецПроцедуры
Что даёт объект сеанса:
- 👤
Пользователь— тот жеПользовательИнформационнойБазы; - 🖥️
ИмяКомпьютера— компьютер, с которого подключился клиент; - 📱
ИмяПриложения— тип клиента: тонкий, веб, фоновое задание, COM-соединение;ПредставлениеПриложения()превращает его в читаемый текст; - ⏱️
НачалоСеансаиНомерСеанса— для аудита и поиска в журнале регистрации.
Список всех сеансов базы возвращает ПолучитьСеансыИнформационнойБазы(). Это удобно, чтобы перед обновлением показать, кто ещё работает. Функция требует административных прав, поэтому вызывайте её в привилегированном режиме или из-под администратора.
Есть и более простые функции глобального контекста: НомерСеансаИнформационнойБазы() и ИмяКомпьютера(). Под «метаданными» в задаче определения пользователя обычно имеют в виду проверку ролей через Метаданные.Роли — она описана в предыдущем разделе.
Фоновые задания, внешнее соединение и HTTP-сервисы
Код выполняется не только в интерактивном сеансе. В каждом случае ответ на вопрос «кто текущий пользователь» свой.
| Где работает код | Кто текущий пользователь |
|---|---|
| Фоновое задание, запущенное из формы | Пользователь, который его запустил |
| Регламентное задание | Пользователь из настроек задания; если не указан — имя будет пустым |
| Внешнее соединение (COM) | Пользователь из строки соединения Usr= |
| HTTP-сервис, веб-сервис | Пользователь, под которым прошла аутентификация публикации |
Из этого следует простое правило: в коде, который может работать без интерактивного входа, всегда проверяйте результат.
Если ПустаяСтрока(ИмяПользователя()) Тогда
// сеанс без имени: регламентное задание без указанного пользователя
// или база без списка пользователей
Ответственный = Справочники.Пользователи.ПустаяСсылка();
Иначе
Ответственный = Пользователи.ТекущийПользователь();
КонецЕсли;
Для регламентных заданий, которые пишут документы, задайте конкретного служебного пользователя в настройках задания. Тогда в реквизите «Автор» будет понятное имя вместо пустого значения.
Ошибки при определении пользователя
Ниже — проблемы, которые всплывают уже после того, как код написан и отлажен на своей базе.
Ещё одна частая ловушка — вызывать Пользователи.ТекущийПользователь() в цикле по тысячам строк табличной части. Функция кэширует результат в параметре сеанса, но всё равно получите значение один раз до цикла и сохраните в переменную. Код станет и быстрее, и читаемее.
Частые вопросы
Чем ИмяПользователя() отличается от ПолноеИмяПользователя()?
Можно ли узнать пароль пользователя программно?
Пароль объекта пользователя ИБ можно установить, но прочитать исходное значение нельзя.Как узнать доменную учётную запись Windows текущего пользователя?
ПользовательОС у результата ПользователиИнформационнойБазы.ТекущийПользователь(). Значение заполнено, только если для пользователя включена аутентификация операционной системы.Меняется ли текущий пользователь в привилегированном режиме?
УстановитьПривилегированныйРежим(Истина) снимает проверку прав, но ИмяПользователя() и Пользователи.ТекущийПользователь() по-прежнему возвращают того, кто вошёл в базу.