Как получить и идентифицировать пользователя, вызвавшего веб-сервис в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции «1С:Предприятия» с внешними системами (мобильными приложениями, сайтами, личными кабинетами) через веб-сервисы (SOAP) или HTTP-сервисы часто возникает задача ведения истории изменений. Автор темы столкнулся с классической проблемой: при записи объектов через веб-сервис стандартная подсистема версионирования БСП (Библиотеки Стандартных Подсистем) записывает изменения на одного системного пользователя, под которым опубликована база. Нам нужно разобраться, как сделать так, чтобы система видела реального инициатора изменений, и при этом избежать масштабного переписывания существующего кода.

В этой статье мы подробно разберем механизмы авторизации в веб-сервисах 1С, выясним, как платформа определяет текущего пользователя, и рассмотрим эффективные архитектурные решения, включая «лайфхак» с динамической подменой параметров сеанса.

Как платформа 1С определяет пользователя в веб-сессиях

Когда внешний клиент обращается к веб-сервису или HTTP-сервису, платформа запускает полноценный сеанс 1С. То, какого пользователя вернет обращение к ПараметрыСеанса.ТекущийПользователь или вызов функции БСП Пользователи.АвторизованныйПользователь(), целиком и полностью зависит от настроек авторизации на веб-сервере (IIS или Apache) и в файле публикации default.vrd.

Рассмотрим два основных сценария авторизации:

  1. Анонимный доступ с жестко прописанным пользователем. Если в файле публикации default.vrd в строке подключения к базе данных (параметр ib) жестко указаны имя пользователя и пароль (например, usr=WebServiceUser;pwd=SecretPassword;), то все без исключения вызовы со всех внешних устройств будут выполняться в контексте этого одного системного пользователя. В этом случае 1С «из коробки» не сможет узнать, кто именно нажал кнопку на стороне сайта или мобильного приложения.
  2. Базовая авторизация (Basic Auth). Если в файле публикации логин и пароль пользователя 1С не зашиты, веб-сервер будет требовать от клиента передачу учетных данных в HTTP-заголовке Authorization при каждом запросе. Если у каждого физического пользователя есть своя учетная запись в справочнике «Пользователи» 1С, и внешняя система передает именно его логин и пароль, то сеанс будет запущен под конкретным пользователем. При этом стандартное версионирование и Журнал регистрации будут работать автоматически, фиксируя действия реального человека без написания дополнительного кода.

Однако на практике использовать индивидуальную базовую авторизацию для сотен мобильных клиентов небезопасно и неудобно в администрировании. Ниже мы разберем альтернативные варианты решения этой задачи.

Вариант 1. Программная подмена параметров сеанса на лету (лучший «лайфхак»)

Если мы хотим оставить единую системную учетную запись для авторизации на веб-сервере, но при этом разделять авторов изменений в отчетах по версионированию, мы можем использовать программную подмену параметров сеанса. Это позволит нам обойтись «парой строчек кода» в самом сервисе и не менять сигнатуры бизнес-методов.

Идея заключается в следующем: внешнее приложение передает уникальный идентификатор или имя реального пользователя в HTTP-заголовках запроса. При обработке запроса в 1С мы считываем этот заголовок и принудительно перезаписываем значение параметра сеанса ТекущийПользователь.

Давайте разберем по шагам, как это реализовать:

Шаг 1. Передача заголовка со стороны клиента. Внешний софт при отправке HTTP-запроса добавляет кастомный заголовок, например, X-Current-Worker, в котором передает имя или GUID пользователя. Для проверки таких запросов подойдёт обработка для тестирования HTTP-сервисов с возможностью редактирования заголовков.

Шаг 2. Перехват и подмена в модуле сервиса. В самом начале выполнения метода нашего сервиса мы выполняем переинициализацию параметра сеанса. Проанализируем следующий пример кода:


// Пример для HTTP-сервиса
Функция ВыполнитьИмпортДанных(Запрос)
    
    // Получаем имя реального пользователя из кастомного заголовка
    ИмяРеальногоПользователя = Запрос.Заголовки.Получить("X-Current-Worker");
    
    Если ЗначениеЗаполнено(ИмяРеальногоПользователя) Тогда
        // Ищем пользователя в справочнике "Пользователи"
        НайденныйПользователь = Справочники.Пользователи.НайтиПоНаименованию(ИмяРеальногоПользователя);
        
        Если ЗначениеЗаполнено(НайденныйПользователь) Тогда
            // Устанавливаем привилегированный режим для записи параметра сеанса
            УстановитьПривилегированныйРежим(Истина);
            
            // Подменяем текущего пользователя для контекста выполняющегося запроса
            ПараметрыСеанса.ТекущийПользователь = НайденныйПользователь;
            
            УстановитьПривилегированныйРежим(Ложь);
        КонецЕсли;
    КонецЕсли;
    
    // Далее следует основной прикладной код создания или изменения объектов
    // Любые подписки на события (включая БСП версионирование) запишут объект от имени НайденныйПользователь
    
    Возврат Новый HTTPСервисОтвет(200);
КонецФункции

Благодаря этому решению стандартный механизм версионирования БСП, который срабатывает в подписке на событие ПередЗаписью или ПриЗаписи объектов и считывает данные из ПараметрыСеанса.ТекущийПользователь, зафиксирует изменения под именем реального сотрудника.

Вариант 2. Передача пользователя в качестве параметра метода (SOAP)

Если мы используем классический Web-сервис (SOAP), работающий по строго описанной WSDL-схеме, мы можем добавить дополнительный входящий параметр во все экспортируемые методы. Например, параметр UserLogin типа string.

Рассмотрим пример реализации метода SOAP-сервиса с явным поиском и установкой пользователя:


Функция ЗаписатьДокументПродажи(ДанныеДокумента, ИмяПользователя) Экспорт
    
    // Инициализируем пользователя перед началом транзакции записи
    Если ЗначениеЗаполнено(ИмяПользователя) Тогда
        ПользовательСсылка = Справочники.Пользователи.НайтиПоРеквизиту("ИдентификаторДляВнешнихСистем", ИмяПользователя);
        Если ЗначениеЗаполнено(ПользовательСсылка) Тогда
            УстановитьПривилегированныйРежим(Истина);
            ПараметрыСеанса.ТекущийПользователь = ПользовательСсылка;
            УстановитьПривилегированныйРежим(Ложь);
        КонецЕсли;
    КонецЕсли;
    
    // Логика создания и проведения документа
    // ...
    
    Возврат Истина;
КонецФункции

Этот способ надежен, но требует модификации WSDL-схемы сервиса и обновления интеграционного кода на стороне всех внешних потребителей, что не всегда возможно или желательно.

Важный технический нюанс: Пул соединений и переиспользование сеансов

При работе с веб-сервисами крайне важно учитывать такой механизм платформы 1С, как пул соединений (Session Pooling). В файле настроек публикации default.vrd параметры пула (такие как reuseSessions или poolSize) определяют, что сеансы после выполнения запроса не уничтожаются сразу, а засыпают и возвращаются в пул для повторного использования последующими запросами.

В чем заключается опасность при подмене параметров сеанса?

Если Запрос №1 пришел от Пользователя А, и мы программно записали в ПараметрыСеанса.ТекущийПользователь ссылку на Пользователя А, то после завершения работы запроса сеанс вернется в пул. Если следующий Запрос №2 от Пользователя Б попадет в этот же повторно используемый сеанс и по какой-то причине не передаст заголовок идентификации (или произойдет сбой чтения), то в параметре сеанса ТекущийПользователь останется «грязное» значение от предыдущего вызова — то есть Пользователь А.

Чтобы избежать подобных ошибок, проанализируем и внедрим следующие правила разработки:

  1. Обязательно очищайте или переопределяйте параметры сеанса при каждом входящем запросе. Если заголовок пользователя пуст, принудительно сбрасывайте ПараметрыСеанса.ТекущийПользователь на дефолтного системного пользователя.
  2. Используйте предопределенную процедуру УстановкаПараметровСеанса в Модуле сеанса для гарантированного контроля инициализации параметров при старте и переиспользовании сеанса веб-сервиса.

Пример безопасного сброса параметров сеанса в обработчике запроса:


// Безопасный сброс параметров в начале обработки любого запроса
УстановитьПривилегированныйРежим(Истина);
// Сначала сбрасываем на дефолтного пользователя интеграции
ПараметрыСеанса.ТекущийПользователь = Справочники.Пользователи.НайтиПоРеквизиту("ИмяВхода", "SystemWebServiceUser");
УстановитьПривилегированныйРежим(Ложь);

// И только потом пытаемся прочитать переданного в заголовке реального пользователя
// ... код чтения заголовка и поиска пользователя ...

Используя предложенные методики, вы сможете легко и элегантно подружить механизмы интеграции через веб-сервисы со стандартной подсистемой версионирования БСП без необходимости переписывать бизнес-логику конфигурации.

← На главную