При разработке на платформе «1С:Предприятие 8» (особенно под управляемый интерфейс) часто возникает задача выполнить определенные действия при самом старте системы. Например, нам может потребоваться проверить права пользователя, установить для него специализированные настройки интерфейса, заблокировать вход определенной группе лиц или запустить систему в режиме киоска. Традиционно для этих целей используется предопределенная процедура ПередНачаломРаботыСистемы(), расположенная в модуле управляемого приложения.
Однако на этом этапе разработчики часто сталкиваются со следующей проблемой: привычные методы получения текущего пользователя либо вызывают ошибки компиляции, либо возвращают пустые значения. В этой статье мы подробно разберем, как устроен жизненный цикл запуска системы 1С, почему возникают сложности с контекстом исполнения и какими способами можно гарантированно и правильно определить пользователя в процедуре ПередНачаломРаботыСистемы().
Среди разработчиков 1С существует распространенное заблуждение, будто в момент вызова процедуры ПередНачаломРаботыСистемы() параметры сеанса еще не инициализированы платформой, и именно поэтому к ним нельзя обратиться. Давайте разберем реальный порядок инициализации и запуска клиентского приложения:
УстановкаПараметровСеанса (с параметром Неопределено в качестве массива имен).ПередНачаломРаботыСистемы() на клиенте.Отказ не был установлен в значение Истина, вызывается процедура ПриНачалеРаботыСистемы().Таким образом, параметры сеанса на сервере уже давно инициализированы к моменту начала работы клиента! Настоящая причина проблемы кроется исключительно в контексте исполнения. Процедура ПередНачаломРаботыСистемы() выполняется строго на клиенте (в тонком, толстом или веб-клиенте). Объект ПараметрыСеанса физически недоступен на клиенте в тонком и веб-клиентах, попытка прямого обращения к нему вызовет ошибку компиляции кода. Чтобы получить параметры сеанса, нам необходимо совершить явный переход с клиента на сервер.
Самый простой и быстрый способ узнать, кто запускает систему, — использовать стандартную глобальную функцию встроенного языка ИмяПользователя(). Она доступна непосредственно на клиенте, поэтому ее можно вызывать без каких-либо дополнительных серверных вызовов.
Рассмотрим пример использования:
Процедура ПередНачаломРаботыСистемы(Отказ)
ТекущееИмя = ИмяПользователя();
Если СокрЛП(ТекущееИмя) = "Администратор" Тогда
// Выполняем действия для администратора
КонецЕсли;
КонецПроцедуры
Важные нюансы и ограничения:
Несмотря на простоту, у этого метода есть существенные недостатки:
ИмяПользователя() на самом раннем этапе запуска в процедуре ПередНачаломРаботыСистемы() может вернуть пустую строку. При этом визуально в заголовке программы имя будет отображаться корректно, так как платформа позже получит эти данные.Пользователи. Если ваша логика завязана на реквизиты справочника, вам все равно придется искать элемент по имени или уникальному идентификатору.Если нам необходимо получить полную информацию о пользователе информационной базы (его уникальный идентификатор, настройки, имя для входа) или безопасно обратиться к параметрам сеанса, мы должны использовать серверный вызов.
Для этого создадим общий модуль с установленными свойствами «Сервер» и «Вызов сервера» (например, с именем РаботаСПользователямиСервер). Реализуем в нем следующую функцию:
Функция ПолучитьДанныеТекущегоПользователя() Экспорт
Результат = Новый Структура;
Результат.Вставить("Имя", "");
Результат.Вставить("УникальныйИдентификатор", Неопределено);
ТекущийПользовательИБ = ПользователиИнформационнойБазы.ТекущийПользователь();
Если ТекущийПользовательИБ <> Неопределено Тогда
Результат.Имя = ТекущийПользовательИБ.Имя;
Результат.УникальныйИдентификатор = ТекущийПользовательИБ.УникальныйИдентификатор;
КонецЕсли;
Возврат Результат;
КонецФункции
Теперь мы можем легко и безопасно вызвать эту функцию на клиенте в модуле управляемого приложения:
Процедура ПередНачаломРаботыСистемы(Отказ)
ДанныеПользователя = РаботаСПользователямиСервер.ПолучитьДанныеТекущегоПользователя();
ИмяИБ = ДанныеПользователя.Имя;
УИД = ДанныеПользователя.УникальныйИдентификатор;
// Пример поиска пользователя в справочнике "Пользователи" по УИД
СсылкаНаПользователя = РаботаСПользователямиСервер.НайтиПользователяПоУИД(УИД);
КонецПроцедуры
Этот подход полностью решает проблему работы в веб-клиенте, поскольку на стороне сервера платформа гарантированно обладает всей информацией о текущем сеансе и авторизованном пользователе.
Если ваша конфигурация разработана на основе Библиотеки стандартных подсистем (БСП), вам не нужно писать собственные велосипеды для связи пользователей информационной базы со справочником Пользователи. В БСП для этого предусмотрены готовые механизмы.
Для определения текущего авторизованного пользователя (который является элементом справочника Пользователи) мы можем использовать функцию общего модуля ПользователиКлиентСервер.АвторизованныйПользователь(). Проанализируем, как устроен этот механизм изнутри:
Функция ТекущийПользователь() Экспорт
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
Возврат Пользователи.ТекущийПользователь();
#Иначе
Возврат ПользователиКлиент.ТекущийПользователь();
#КонецЕсли
КонецФункции
Важное предостережение при работе с БСП:
В БСП активно применяется кэширование данных на клиенте для оптимизации производительности. В момент выполнения процедуры ПередНачаломРаботыСистемы() клиентский кэш БСП может быть еще не инициализирован до конца. Поэтому попытка получить пользователя напрямую через ПользователиКлиент.ТекущийПользователь() может вернуть пустую ссылку или вызвать ошибку инициализации параметров сеанса.
Для надежного обхода этой проблемы рекомендуется принудительно запрашивать авторизованного пользователя через серверную функцию БСП:
Процедура ПередНачаломРаботыСистемы(Отказ)
// Надежное получение ссылки на элемент справочника "Пользователи" через БСП
ТекущийПользовательСправочник = ОбщегоНазначенияВызовСервера.ИндексВызова(
"Пользователи.АвторизованныйПользователь"
);
// Либо прямой вызов серверной функции БСП, если это допустимо в вашей версии
ТекущийПользовательСправочник = Пользователи.АвторизованныйПользователь();
КонецПроцедуры
Зачастую определение пользователя в процедуре ПередНачаломРаботыСистемы() требуется лишь для того, чтобы проверить его права (например, разрешено ли ему запускать программу или выполнять административные функции).
Обратите внимание, что на момент выполнения этого события роли пользователя уже полностью прочитаны платформой и активны. Вы можете проверять доступность ролей непосредственно на клиенте без переходов на сервер с помощью стандартной функции РольДоступна():
Процедура ПередНачаломРаботыСистемы(Отказ)
// Проверка роли непосредственно на клиенте без обращения к серверу
Если Не РольДоступна("ПолныеПрава") И Не РольДоступна("ИнтерфейсКассира") Тогда
Предупреждение("У вас нет прав на запуск данного рабочего места!");
Отказ = Истина;
КонецЕсли;
КонецПроцедуры
Тем не менее, если вам требуется проверить сложные ограничения (например, доступ по RLS или дополнительные настройки из справочников), рекомендуется переносить логику проверки на сторону сервера, передавая на клиент лишь итоговый вердикт (разрешить запуск или нет).
Подводя итоги, выделим лучшие практики для определения пользователя при старте системы:
ИмяПользователя() только для простейших отладочных сценариев или в базах, где гарантированно не будет использоваться веб-клиент и доменная авторизация.Пользователи.АвторизованныйПользователь(), вызываемой в серверном контексте, чтобы получить ссылку на справочник пользователей с учетом всех установленных прав и замещений.РольДоступна(), чтобы минимизировать нагрузку на сервер при запуске приложения.