Текущий пользователь 1С — это три разных значения, и путаница между ними даёт большую часть ошибок в доработках. Платформа знает пользователя информационной базы: строку ИмяПользователя() и объект ПользователиИнформационнойБазы.ТекущийПользователь() с именем, полным именем, идентификатором и ролями. В конфигурациях на БСП к нему привязан элемент справочника «Пользователи»: его возвращает Пользователи.ТекущийПользователь(), и именно эта ссылка попадает в реквизиты «Ответственный» и «Автор».
Ниже — как получить каждое значение программно на сервере и на клиенте, проверить роль, заполнить автора документа, отобрать свои документы запросом и не потерять пользователя в фоновом задании. Код для платформы 8.3 и БСП 3.x; роль «СменаОтветственных», константа и регламентное задание обмена — условные объекты доработки.
| Что нужно | Вызов | Результат | Где работает |
|---|---|---|---|
| Имя для входа | ИмяПользователя() | Строка | клиент и сервер |
| Полное имя | ПолноеИмяПользователя() | Строка | клиент и сервер |
| Роли, идентификатор, настройки входа | ПользователиИнформационнойБазы.ТекущийПользователь() | ПользовательИнформационнойБазы | сервер, толстый клиент, внешнее соединение |
| Ссылка для реквизитов и запросов | Пользователи.ТекущийПользователь() | СправочникСсылка.Пользователи | сервер, БСП |
| Пользователь или внешний пользователь | Пользователи.АвторизованныйПользователь() | ссылка на «Пользователи» или «Внешние пользователи» | сервер, БСП |
| Ссылка без вызова сервера | ПользователиКлиент.ТекущийПользователь() | СправочникСсылка.Пользователи | клиент, БСП 3.x |
Строку имени для связей не используют: администратор переименует пользователя, и сравнения по имени перестанут находить записи. Хранят ссылку на справочник, а с пользователем ИБ сопоставляют по УникальныйИдентификатор — при переименовании он не меняется.
Объект пользователя ИБ доступен на сервере, в толстом клиенте и во внешнем соединении. Нужные свойства удобно собрать в структуру в общем модуле с флагами «Сервер» и «Вызов сервера» — тогда её получит и клиентский код.
// Общий модуль ТекущийПользовательВызовСервера, флаги «Сервер» и «Вызов сервера».
// Возвращает сведения о пользователе ИБ текущего сеанса.
//
// Возвращаемое значение:
// Структура - Имя, ПолноеИмя, Идентификатор, БезПользователяИБ, Роли, ПолныеПрава.
//
Функция СведенияОПользователеИБ() Экспорт
ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
Сведения = Новый Структура;
Сведения.Вставить("Имя", ПользовательИБ.Имя);
Сведения.Вставить("ПолноеИмя", ПользовательИБ.ПолноеИмя);
Сведения.Вставить("Идентификатор", ПользовательИБ.УникальныйИдентификатор);
Сведения.Вставить("БезПользователяИБ", ПустаяСтрока(ПользовательИБ.Имя));
// Роли, назначенные пользователю в списке пользователей.
Роли = Новый Массив;
Для Каждого Роль Из ПользовательИБ.Роли Цикл
Роли.Добавить(Роль.Имя);
КонецЦикла;
Сведения.Вставить("Роли", Роли);
// Роли, с которыми реально работает сеанс.
Сведения.Вставить("ПолныеПрава", РольДоступна(Метаданные.Роли.ПолныеПрава));
Возврат Сведения;
КонецФункции
ПользовательИБ.Роли — коллекция ролей из списка пользователей; каждый элемент — объект метаданных со свойствами Имя и Синоним.Имя означает сеанс без пользователя ИБ: база с пустым списком пользователей или регламентное задание, для которого пользователь не указан.РольДоступна(): она отвечает за роли сеанса. В базе без пользователей это роли из свойства конфигурации «Основные роли».В типовых конфигурациях ссылку дают функции общего модуля Пользователи: ТекущийПользователь() и АвторизованныйПользователь(). Вторая нужна там, где в программу входят и внешние пользователи (личный кабинет контрагента): в их сеансе ТекущийПользователь() вызывает исключение. Значения хранятся в параметрах сеанса БСП ТекущийПользователь и ТекущийВнешнийПользователь, но читать их напрямую не нужно — API учитывает права и внешних пользователей. Устройство библиотеки описано в статье о БСП.
В конфигурации без БСП ту же схему собирают вручную: параметр сеанса ТекущийПользователь типа СправочникСсылка.Пользователи, реквизит справочника ИдентификаторПользователяИБ и модуль сеанса.
// Модуль сеанса конфигурации без БСП.
// Параметр сеанса ТекущийПользователь: СправочникСсылка.Пользователи.
// Реквизит справочника ИдентификаторПользователяИБ: УникальныйИдентификатор.
Процедура УстановкаПараметровСеанса(ТребуемыеПараметры)
Если ТребуемыеПараметры = Неопределено
Или ТребуемыеПараметры.Найти("ТекущийПользователь") <> Неопределено Тогда
ПараметрыСеанса.ТекущийПользователь = ПользовательСправочника();
КонецЕсли;
КонецПроцедуры
Функция ПользовательСправочника()
ПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
Если ПустаяСтрока(ПользовательИБ.Имя) Тогда
// База без пользователей или регламентное задание без пользователя.
Возврат Справочники.Пользователи.ПустаяСсылка();
КонецЕсли;
Запрос = Новый Запрос(
"ВЫБРАТЬ ПЕРВЫЕ 1
| Пользователи.Ссылка КАК Ссылка
|ИЗ
| Справочник.Пользователи КАК Пользователи
|ГДЕ
| Пользователи.ИдентификаторПользователяИБ = &Идентификатор");
Запрос.УстановитьПараметр("Идентификатор", ПользовательИБ.УникальныйИдентификатор);
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Ссылка;
КонецЕсли;
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Пользователь ИБ ""%1"" не сопоставлен с элементом справочника Пользователи.'"),
ПользовательИБ.Имя);
КонецФункции
ТребуемыеПараметры = Неопределено — вызов при старте сеанса; массив имён — обращение к параметру, который ещё не установлен.В тонком и веб-клиенте нет ни ПользователиИнформационнойБазы, ни ПараметрыСеанса, ни серверного модуля Пользователи. Без обращения к серверу доступны имя, полное имя и в БСП 3.x ссылка на справочник; роли — только через серверный вызов.
// Модуль формы документа в конфигурации на БСП 3.x.
// Команды формы: НазначитьМеня и КтоЯ.
&НаКлиенте
Процедура НазначитьМеня(Команда)
// Ссылка из параметров клиента: вызова сервера нет.
Объект.Ответственный = ПользователиКлиент.ТекущийПользователь();
Модифицированность = Истина;
КонецПроцедуры
&НаКлиенте
Процедура КтоЯ(Команда)
// Имя и полное имя доступны на клиенте.
ИмяДляВхода = ИмяПользователя();
Если ПустаяСтрока(ИмяДляВхода) Тогда
ПоказатьПредупреждение(, НСтр("ru = 'Сеанс запущен без пользователя ИБ.'"));
Возврат;
КонецЕсли;
// Роли и права: один серверный вызов.
Сведения = ТекущийПользовательВызовСервера.СведенияОПользователеИБ();
ТекстСообщения = СтрШаблон(НСтр("ru = '%1 (%2). Ролей: %3. Полные права: %4.'"),
ПолноеИмяПользователя(), ИмяДляВхода, Сведения.Роли.Количество(),
Формат(Сведения.ПолныеПрава, "БЛ=нет; БИ=да"));
ПоказатьПредупреждение(, ТекстСообщения);
КонецПроцедуры
ПользователиКлиент.ТекущийПользователь() берёт ссылку из параметров, полученных при запуске программы, поэтому команда «Назначить меня» не обращается к серверу.Модифицированность = Истина.&НаСервереБезКонтекста, читающая ПараметрыСеанса.ТекущийПользователь.Роль проверяет функция платформы РольДоступна(), право на объект — ПравоДоступа(), в БСП есть Пользователи.РолиДоступны() и Пользователи.ЭтоПолноправныйПользователь(). Как создать роль и настроить в ней права, рассказано в статье о ролях 1С.
// Модуль формы списка документов.
// СменаОтветственных — своя роль доработки, команда НазначитьМеняОтветственным.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
// Платформа: есть ли роль у текущего сеанса (имя строкой или объект метаданных).
Элементы.ФормаНазначитьМеняОтветственным.Видимость = РольДоступна("СменаОтветственных")
Или РольДоступна(Метаданные.Роли.ПолныеПрава);
// Платформа: право на объект конфигурации вместо имени роли.
Элементы.ФормаНастройкиОбмена.Видимость = ПравоДоступа("Администрирование", Метаданные);
// БСП: полноправный пользователь.
Элементы.ГруппаСлужебныеКоманды.Видимость = Пользователи.ЭтоПолноправныйПользователь();
КонецПроцедуры
&НаКлиенте
Процедура НазначитьМеняОтветственным(Команда)
Выделенные = Элементы.Список.ВыделенныеСтроки;
Если Выделенные.Количество() = 0 Тогда
Возврат;
КонецЕсли;
НазначитьОтветственногоНаСервере(Выделенные);
Элементы.Список.Обновить();
КонецПроцедуры
&НаСервереБезКонтекста
Процедура НазначитьОтветственногоНаСервере(Знач СписокДокументов)
// Скрытая кнопка не защищает: проверка повторяется на сервере.
Если Не Пользователи.РолиДоступны("СменаОтветственных") Тогда
ВызватьИсключение НСтр("ru = 'Недостаточно прав для смены ответственного.'");
КонецЕсли;
// Пользователя определяет сервер, а не значение, пришедшее с клиента.
НовыйОтветственный = Пользователи.ТекущийПользователь();
НачатьТранзакцию();
Попытка
Для Каждого ДокументСсылка Из СписокДокументов Цикл
ДокументОбъект = ДокументСсылка.ПолучитьОбъект();
ДокументОбъект.Заблокировать();
ДокументОбъект.Ответственный = НовыйОтветственный;
ДокументОбъект.Записать(РежимЗаписиДокумента.Запись);
КонецЦикла;
ЗафиксироватьТранзакцию();
Исключение
ОтменитьТранзакцию();
ВызватьИсключение;
КонецПопытки;
КонецПроцедуры
РольДоступна принимает объект метаданных или имя роли строкой и проверяет роли текущего сеанса.Пользователи.РолиДоступны возвращает Истина, если доступна хотя бы одна роль из списка или пользователь полноправный, — администратору отдельная роль не нужна.Ответственного подставляют при заполнении нового документа, автора — при первой записи. Код размещают в модуле объекта, а не формы: так он сработает и для документов, созданных обработкой, обменом или вводом на основании.
// Модуль объекта документа. Реквизиты Ответственный и Автор: СправочникСсылка.Пользователи.
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Процедура ОбработкаЗаполнения(ДанныеЗаполнения, ТекстЗаполнения, СтандартнаяОбработка)
// Новый документ из формы, ввод на основании, вызов Заполнить().
Если Не ЗначениеЗаполнено(Ответственный) Тогда
Ответственный = Пользователи.ТекущийПользователь();
КонецЕсли;
КонецПроцедуры
Процедура ПриКопировании(ОбъектКопирования)
// При копировании ОбработкаЗаполнения не вызывается.
Ответственный = Пользователи.ТекущийПользователь();
Автор = Справочники.Пользователи.ПустаяСсылка();
КонецПроцедуры
Процедура ПередЗаписью(Отказ, РежимЗаписи, РежимПроведения)
Если ОбменДанными.Загрузка Тогда
Возврат;
КонецЕсли;
Если ЭтоНовый() Тогда
// Автор фиксируется при первой записи, как бы ни создавался документ.
Если Не ЗначениеЗаполнено(Автор) Тогда
Автор = Пользователи.ТекущийПользователь();
КонецЕсли;
// Создан программно без Заполнить(): ответственным становится автор.
Если Не ЗначениеЗаполнено(Ответственный) Тогда
Ответственный = Автор;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
#Иначе
ВызватьИсключение НСтр("ru = 'Недопустимый вызов объекта на клиенте.'");
#КонецЕсли
ОбработкаЗаполнения вызывается при интерактивном создании, вводе на основании и методе Заполнить(). После программного СоздатьДокумент() без Заполнить() она не срабатывает — оба реквизита тогда заполнит ПередЗаписью.ПриКопировании.ОбменДанными.Загрузка не даёт переписать автора у документов, пришедших по обмену.Тот же код можно поместить в ПриСозданииНаСервере формы с условием Параметры.Ключ.Пустая(), но тогда документы, созданные без формы, останутся без ответственного.
В обычном запросе &ТекущийПользователь — параметр запроса: платформа не подставляет туда параметр сеанса, значение передают через УстановитьПараметр. В динамическом списке с произвольным запросом — через Список.Параметры.
// Модуль менеджера документа ЗаказКлиента.
// Возвращает заказы текущего пользователя начиная с указанной даты.
Функция ЗаказыТекущегоПользователя(НачалоПериода) Экспорт
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Ссылка КАК Ссылка,
| Заказ.Номер КАК Номер,
| Заказ.Дата КАК Дата
|ИЗ
| Документ.ЗаказКлиента КАК Заказ
|ГДЕ
| Заказ.Ответственный = &ТекущийПользователь
| И Заказ.Дата >= &НачалоПериода
| И НЕ Заказ.ПометкаУдаления
|
|УПОРЯДОЧИТЬ ПО
| Дата";
// Здесь &ТекущийПользователь — параметр запроса, его задают явно.
Запрос.УстановитьПараметр("ТекущийПользователь", Пользователи.ТекущийПользователь());
Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);
Возврат Запрос.Выполнить().Выгрузить();
КонецФункции
// Модуль формы списка «Мои заказы». В запросе динамического списка
// то же условие: Заказ.Ответственный = &ТекущийПользователь.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
Список.Параметры.УстановитьЗначениеПараметра("ТекущийПользователь",
Пользователи.ТекущийПользователь());
КонецПроцедуры
В ограничениях доступа на уровне записей (RLS) функций вроде ИмяПользователя() нет — текст ограничения видит только параметры сеанса. Поэтому условие «только свои документы» сравнивает поле с &ТекущийПользователь, и здесь это уже параметр сеанса. Отбор в запросе скрывает чужие документы только из одного списка, а RLS действует на любое чтение данных. В конфигурациях на БСП такие ограничения строят через «Управление доступом» и группы доступа, а не правкой текста роли — подробнее в статье о правах доступа.
Фоновое задание, запущенное через ФоновыеЗадания.Выполнить, работает от имени пользователя, который его запустил: Пользователи.ТекущийПользователь() внутри вернёт ту же ссылку, что и в форме. Клиента у фонового сеанса нет, поэтому ПользователиКлиент и диалоги там недоступны. Регламентное задание выполняется от имени пользователя из своего свойства ИмяПользователя; если оно пустое, сеанс работает без пользователя ИБ и ИмяПользователя() возвращает пустую строку.
// Общий модуль ОбменССайтомСервер, флаг «Сервер».
// Константа ОтветственныйЗаОбменомССайтом — настройка доработки.
// Обработчик регламентного задания ОбменССайтом.
Процедура ЗагрузитьЗаказыПоРасписанию() Экспорт
ОбщегоНазначения.ПриНачалеВыполненияРегламентногоЗадания(
Метаданные.РегламентныеЗадания.ОбменССайтом);
ЗагрузитьЗаказы();
КонецПроцедуры
// Запуск вручную из серверной процедуры формы:
// задание работает от имени пользователя, нажавшего кнопку.
Функция ЗапуститьЗагрузкуВФоне() Экспорт
Задание = ФоновыеЗадания.Выполнить("ОбменССайтомСервер.ЗагрузитьЗаказы", ,
"ОбменССайтом", НСтр("ru = 'Загрузка заказов с сайта'"));
Возврат Задание.УникальныйИдентификатор;
КонецФункции
Процедура ЗагрузитьЗаказы() Экспорт
Ответственный = ОтветственныйЗаЗагрузку();
ЗаписьЖурналаРегистрации(
НСтр("ru = 'Обмен с сайтом.Загрузка'", ОбщегоНазначения.КодОсновногоЯзыка()),
УровеньЖурналаРегистрации.Информация, , ,
СтрШаблон(НСтр("ru = 'Пользователь сеанса: ""%1"", ответственный: %2'"),
ИмяПользователя(), Ответственный));
// Далее создаются заказы с реквизитом Ответственный = Ответственный.
КонецПроцедуры
Функция ОтветственныйЗаЗагрузку()
// Фоновое задание или регламентное с указанным пользователем.
Если Не ПустаяСтрока(ИмяПользователя()) Тогда
Возврат Пользователи.ТекущийПользователь();
КонецЕсли;
// Регламентное задание без пользователя ИБ.
Ответственный = Константы.ОтветственныйЗаОбменомССайтом.Получить();
Если Не ЗначениеЗаполнено(Ответственный) Тогда
ВызватьИсключение НСтр("ru = 'Задание выполняется без пользователя, а ответственный за обмен не указан.'");
КонецЕсли;
Возврат Ответственный;
КонецФункции
// Назначить пользователя регламентному заданию (нужны административные права).
Процедура НазначитьПользователяЗаданию(ИмяПользователяИБ) Экспорт
Задание = РегламентныеЗадания.НайтиПредопределенное(Метаданные.РегламентныеЗадания.ОбменССайтом);
Задание.ИмяПользователя = ИмяПользователяИБ;
Задание.Записать();
КонецПроцедуры
Кто сейчас работает в базе, показывает ПолучитьСеансыИнформационнойБазы(): массив сеансов со свойствами НомерСеанса, Пользователь, ИмяПриложения, ИмяКомпьютера, НачалоСеанса. Номер своего сеанса возвращает НомерСеансаИнформационнойБазы().
// Модуль формы обработки «Активные сеансы».
// Реквизит Сеансы — таблица значений с колонками НомерСеанса, Пользователь,
// Приложение, Компьютер, Начало, ЭтоТекущий.
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
ЗаполнитьСеансы();
КонецПроцедуры
&НаКлиенте
Процедура ОбновитьСеансы(Команда)
ЗаполнитьСеансы();
КонецПроцедуры
&НаСервере
Процедура ЗаполнитьСеансы()
Сеансы.Очистить();
НомерТекущегоСеанса = НомерСеансаИнформационнойБазы();
УстановитьПривилегированныйРежим(Истина);
МассивСеансов = ПолучитьСеансыИнформационнойБазы();
УстановитьПривилегированныйРежим(Ложь);
Для Каждого Сеанс Из МассивСеансов Цикл
СтрокаСеанса = Сеансы.Добавить();
СтрокаСеанса.НомерСеанса = Сеанс.НомерСеанса;
СтрокаСеанса.Приложение = ПредставлениеПриложения(Сеанс.ИмяПриложения);
СтрокаСеанса.Компьютер = Сеанс.ИмяКомпьютера;
СтрокаСеанса.Начало = Сеанс.НачалоСеанса;
СтрокаСеанса.ЭтоТекущий = (Сеанс.НомерСеанса = НомерТекущегоСеанса);
// У сеанса без пользователя ИБ свойство Пользователь не заполнено.
Если Сеанс.Пользователь = Неопределено Тогда
СтрокаСеанса.Пользователь = НСтр("ru = '<без пользователя>'");
Иначе
СтрокаСеанса.Пользователь = Сеанс.Пользователь.ПолноеИмя;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
ПредставлениеПриложения() превращает служебное имя («1CV8C», «BackgroundJob») в читаемое «Тонкий клиент», «Фоновое задание».Пользователь проверяют на Неопределено: без проверки код упадёт на первом сеансе без пользователя ИБ.&НаКлиенте. Так же выглядят ошибки с Пользователи и ПараметрыСеанса. На клиенте используйте ИмяПользователя(), ПользователиКлиент или серверный вызов; в конфигурации без БСП модуля Пользователи нет вовсе.Запрос.УстановитьПараметр.ИмяПользователя(), получил пустую строку и пустую ссылку. Обрабатывайте пустое имя явно; БСП в такой базе подставляет служебного пользователя «<Не указан>».Сеанс.Пользователь.ПолноеИмя, когда у сеанса нет пользователя ИБ.Метаданные.Роли.ПолныеПрава в конфигурации, где роль называется иначе. Сверьте имя в дереве метаданных.Usr и Pwd пользователя базы. Код работает от его имени, клиентских модулей там нет, а в ролях нужно право «Внешнее соединение».Функция платформы возвращает строку — имя для входа. Функция БСП возвращает ссылку на элемент справочника «Пользователи». В реквизиты и запросы пишут ссылку, строку — в сообщения и журналы.
ИмяПользователя() и ПолноеИмяПользователя() работают на клиенте. В конфигурациях на БСП 3.x ссылку на справочник даёт ПользователиКлиент.ТекущийПользователь(); роли и идентификатор пользователя ИБ — только на сервере.
От имени пользователя, который его запустил, с теми же ролями. Регламентное задание — от пользователя из его настроек; если пользователь не указан, ИмяПользователя() вернёт пустую строку.
В БСП — Пользователи.ЭтоПолноправныйПользователь(). Без БСП — РольДоступна(Метаданные.Роли.ПолныеПрава), а если такой роли нет — ПравоДоступа("Администрирование", Метаданные).
Разграничить документы по ответственным, настроить RLS и журнал действий пользователей в типовой конфигурации без поломки обновлений быстрее поручить программисту 1С. Опишите задачу и версию конфигурации на странице размещения задания — исполнители предложат решение и сроки.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.