При разработке интеграционных решений на платформе 1С:Предприятие часто возникает ситуация, когда необходимо обратиться к веб-сервису, защищенному с помощью Windows-аутентификации. Стандартное поведение системы в этом случае может преподнести сюрприз: вместо того чтобы просто вернуть код ошибки 401 (Unauthorized) в программный код, операционная система перехватывает управление и выводит пользователю диалоговое окно для ввода логина и пароля. Это блокирует автоматизацию процесса и вынуждает пользователя совершать лишние действия, такие как нажатие кнопки "Отмена".
В этой статье мы подробно разберем, почему это происходит, и рассмотрим несколько эффективных способов решения этой проблемы, включая использование встроенных объектов 1С и альтернативных COM-объектов Windows.
Для начала проанализируем ситуацию. Когда мы используем COM-объект MSXML2.XMLHTTP.6.0, мы фактически работаем через библиотеку WinInet. Эта библиотека изначально проектировалась для браузера Internet Explorer. Её главная задача — обеспечить интерактивное взаимодействие с пользователем. Если сервер запрашивает авторизацию (отправляет заголовок WWW-Authenticate), WinInet считает своим долгом помочь пользователю и выводит системное окно ввода учетных данных.
Если же наша задача — реализовать "тихий" запрос, который должен либо выполниться под текущим пользователем ОС, либо вернуть 401 для дальнейшей обработки логикой 1С, нам нужно либо сменить инструмент, либо изменить настройки текущего.
Рассмотрим наиболее правильный способ для современной платформы 1С. Встроенный объект HTTPСоединение обладает параметром, который позволяет управлять Windows-аутентификацией напрямую, не вызывая лишних диалогов. Как отметил автор исходной темы, этот метод является наиболее стабильным.
Разберем пример кода, который позволяет выполнить запрос прозрачно:
// Определяем параметры подключения
Сервер = "myserver.local";
Ресурс = "/MyBase/hs/my_service/v1/data";
// Ключевой момент: параметр ИспользоватьАутентификациюОС = Истина
// Это заставляет 1С использовать текущий токен пользователя Windows
Соединение = Новый HTTPСоединение(Сервер, , , , , , , Истина);
Запрос = Новый HTTPЗапрос(Ресурс);
// Добавляем необходимые заголовки, если нужно
Запрос.Заголовки.Вставить("Content-Type", "application/xml");
Попытка
Ответ = Соединение.ВызватьHTTPМетод("POST", Запрос);
КодСостояния = Ответ.КодСостояния;
Если КодСостояния = 200 Тогда
// Обрабатываем успешный ответ
Сообщить("Запрос выполнен успешно под пользователем ОС");
ИначеЕсли КодСостояния = 401 Тогда
// Окно не появилось, мы получили управление и можем
// реализовать логику создания пользователя или регистрации
Сообщить("Пользователь не авторизован, выполняем регистрацию...");
КонецЕсли;
Исключение
// Обработка сетевых ошибок
Сообщить("Ошибка при выполнении запроса: " + ОписаниеОшибки());
КонецПопытки;
Использование HTTPСоединение с флагом ИспользоватьАутентификациюОС решает проблему в большинстве случаев на платформе 8.3. Однако, если ваша конфигурация работает в режиме совместимости со старыми версиями (например, 8.2 или ранние 8.3), этот функционал может быть недоступен или работать некорректно.
Если по каким-то причинам вы обязаны использовать COM-объекты (например, при работе в очень старых конфигурациях или специфических окружениях), следует заменить MSXML2.XMLHTTP на MSXML2.ServerXMLHTTP или напрямую на WinHttp.WinHttpRequest.5.1.
Объект ServerXMLHTTP базируется на библиотеке WinHTTP. В отличие от WinInet, она создана для серверных приложений и сервисов. У неё нет интерфейса пользователя, поэтому она физически не может вывести окно ввода пароля. Если аутентификация не удалась, она просто вернет ошибку или код 401.
Проанализируем пример использования WinHttpRequest:
WinHTTP = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
WinHTTP.Open("POST", АдресЗапроса, Ложь);
// Установка политики автоматического входа
// 0 - AutoLogonPolicy_Always
// 1 - AutoLogonPolicy_OnlyIfSensitive
// 2 - AutoLogonPolicy_Never (запретить автоматический вход и окна)
WinHTTP.SetAutoLogonPolicy(2);
WinHTTP.Send(ТелоЗапроса);
КодОтвета = WinHTTP.Status;
Если КодОтвета = 401 Тогда
// Мы получили 401 без всяких окон!
// Здесь ваша логика по созданию пользователя
КонецЕсли;
Метод SetAutoLogonPolicy(2) гарантирует, что объект даже не будет пытаться использовать учетные данные текущего пользователя, что моментально приведет к получению 401 от сервера IIS, если анонимный доступ закрыт.
Иногда полезно "обмануть" библиотеку WinInet, передав ей пустые или заведомо неверные данные в методе Open. Когда объект видит, что программист уже предоставил учетные данные (даже если они неверны), он часто подавляет попытку вызова системного окна.
Посмотрим на пример модификации исходного кода:
XMLHTTP = Новый COMОбъект("MSXML2.XMLHTTP.6.0");
// Передаем пустые строки в качестве логина и пароля
XMLHTTP.Open("POST", Адрес, Ложь, " ", " ");
XMLHTTP.Send(Запрос);
КодОтвета = XMLHTTP.Status;
Этот метод менее надежен, чем использование WinHTTP, но в некоторых специфических конфигурациях безопасности Windows он помогает избежать появления окна.
Существует стандарт де-факто: если запрос является асинхронным (AJAX), сервер не должен запрашивать интерактивную авторизацию. Выясним, как мы можем это использовать. Многие веб-серверы (включая IIS, на котором обычно публикуется 1С) проверяют наличие заголовка X-Requested-With.
Попробуем добавить этот заголовок в наш запрос:
XMLHTTP.setRequestHeader("X-Requested-With", "XMLHttpRequest");
В некоторых случаях правильно настроенный IIS, увидев этот заголовок, при ошибке авторизации отправит чистый код 401 без предложения пройти NTLM/Negotiate проверку в интерактивном режиме.
Если вы контролируете сервер, на котором опубликован веб-сервис 1С, проверьте следующие настройки в диспетчере IIS:
XMLHTTP зависит от настроек "Свойств браузера" в Windows. Если адрес сервера находится в зоне "Местная интрасеть", Windows будет пытаться отправить текущий логин автоматически. Если в зоне "Интернет" — скорее всего, будет запрашивать пароль.Для решения задачи по подавлению окна авторизации мы рекомендуем придерживаться следующего порядка действий:
HTTPСоединение с параметром ИспользоватьАутентификациюОС = Истина. Это самый современный и поддерживаемый платформой способ.XMLHTTP на WinHttp.WinHttpRequest.5.1 и используйте метод SetAutoLogonPolicy(2). Это полностью исключит появление любых интерфейсных окон.Open и добавление заголовка X-Requested-With.Выбрав один из этих методов, вы сможете реализовать гибкую логику обработки авторизации, например, автоматическую регистрацию новых пользователей в базе 1С при их первом обращении к веб-сервису под учетной записью Windows.