При интеграции 1С с внешними веб-ресурсами разработчики часто сталкиваются с задачей автоматического сбора данных (парсинга) с сайтов, защищенных современными системами авторизации (SSO), такими как Keycloak или другие решения на базе протокола OpenID Connect (OIDC). Отличным примером служит портал Московской биржи (MOEX) и связанный с ним ресурс NSDData.
В этой статье мы подробно разберем, как обойти программные ограничения встроенных механизмов 1С (особенно на старых платформах вроде 1С 8.1 или при использовании Обычных форм в 1С 8.3) и настроить надежную авторизацию без использования дорогостоящего платного API.
На первый взгляд самым простым решением кажется вывод формы авторизации на экран через объект ПолеHTMLДокумента, заполнение полей логина/пароля программными методами и программный "клик" по кнопке "Войти". Однако на практике этот подход быстро заходит в тупик по следующим причинам:
ПолеHTMLДокумента в обычных формах использует системный движок Internet Explorer в режиме совместимости. Современные скрипты авторизации Keycloak, написанные с использованием современных стандартов JavaScript, часто работают в нем некорректно или вызывают фатальные ошибки сценариев.id (например, поле ввода логина имеет только имя name="credentials"), что усложняет обращение к ним.Поэтому мы проанализируем и внедрим гораздо более надежный способ — программную эмуляцию HTTP-запросов.
Когда мы нажимаем кнопку "Вход" на целевом сайте, происходит перенаправление на сервер авторизации. Ссылка перенаправления содержит множество параметров:
https://sso.moex.com/auth/realms/moex/protocol/openid-connect/auth
?kc_locale=ru
&response_type=code
&redirect_uri=https%3A%2F%2Fnsddata.ru%2Fru
&client_id=NSDDATA
&nonce=62ffba1566b5c1016d388b3c74f48de2
&state=a2d366b9b88bcd2d14421b147f643dac
&scope=openid
Сервер авторизации Keycloak динамически генерирует форму входа, внедряя в нее уникальные сессионные параметры. Нам необходимо передать POST-запрос на адрес обработчика формы авторизации. Проанализируем структуру этого запроса:
code, execution, client_id и tab_id. Эти данные уникальны для каждого сеанса авторизации.application/x-www-form-urlencoded и содержать следующие параметры:
credentials — e-mail или логин пользователя.password — пароль.CSRF — уникальный защитный токен, сгенерированный сервером при открытии страницы.Поскольку встроенный в 1С объект HTTPСоединение на старых платформах не умеет гибко управлять заголовками и автоматически сохранять куки (Cookies), мы будем использовать внешний COM-объект операционной системы Windows — WinHttp.WinHttpRequest.5.1.
Использование этого объекта решает сразу три важнейшие задачи:
Set-Cookie.Рассмотрим пошаговый алгоритм решения нашей задачи на языке 1С.
Шаг 1. Инициализация объекта WinHttp и настройка параметров безопасности
Создаем COM-объект и устанавливаем необходимые флаги работы с защищенным соединением SSL/TLS.
WinHttp = Новый COMОбъект("WinHttp.WinHttpRequest.5.1");
// Включаем поддержку TLS 1.2 (флаг 2048)
WinHttp.Option(9, 2048);
// Отключаем автоматический редирект, чтобы вручную перехватить код авторизации
WinHttp.Option(6, 0);
Шаг 2. Выполнение первичного GET-запроса для получения CSRF-токена и параметров сессии
Нам необходимо зайти на страницу авторизации, чтобы сервер выдал нам куки сессии и сгенерировал форму с уникальными токенами безопасности.
АдресАвторизации = "https://sso.moex.com/auth/realms/moex/protocol/openid-connect/auth?kc_locale=ru&response_type=code&redirect_uri=https%3A%2F%2Fnsddata.ru%2Fru&client_id=NSDDATA&scope=openid";
WinHttp.Open("GET", АдресАвторизации, Ложь);
WinHttp.SetRequestHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
WinHttp.Send();
Если WinHttp.Status <> 200 Тогда
ВызватьИсключение "Не удалось получить первичную страницу авторизации. Код ошибки: " + WinHttp.Status;
КонецЕсли;
ТекстОтвета = WinHttp.ResponseText;
Шаг 3. Парсинг динамических параметров из HTML-кода страницы
Теперь из полученного текста страницы нам нужно вытащить адрес действия формы (атрибут action тега form) и значение скрытого поля CSRF. Для этого напишем простую вспомогательную функцию поиска подстроки или воспользуемся регулярными выражениями.
// Функция для поиска параметров между двумя тегами/строками
Функция ПолучитьПараметрМеждуСтрок(ТекстИсточник, ЛеваяГраница, ПраваяГраница)
ПозЛевая = Найти(ТекстИсточник, ЛеваяГраница);
Если ПозЛевая = 0 Тогда
Возврат "";
КонецЕсли;
НачалоПоиска = ПозЛевая + СтрДлина(ЛеваяГраница);
ПозПравая = Найти(Сред(ТекстИсточник, НачалоПоиска), ПраваяГраница);
Если ПозПравая = 0 Тогда
Возврат "";
КонецЕсли;
Возврат Сред(ТекстИсточник, НачалоПоиска, ПозПравая - 1);
КонецФункции
Используя эту функцию, извлекаем динамические параметры из полученного HTML-кода:
// Извлекаем action формы (целевой URL для POST запроса)
АдресОбработчикаФормы = ПолучитьПараметрМеждуСтрок(ТекстОтвета, "id=""kc-form-login"" action=""", """");
// Извлекаем CSRF токен
ТокенCSRF = ПолучитьПараметрМеждуСтрок(ТекстОтвета, "name=""CSRF"" value=""", """");
Если ПустаяСтрока(АдресОбработчикаФормы) Или ПустаяСтрока(ТокенCSRF) Тогда
ВызватьИсключение "Не удалось распарсить защитные токены со страницы входа.";
КонецЕсли;
Шаг 4. Отправка POST-запроса с логином и паролем
Теперь мы готовы отправить данные авторизации на сервер. Формируем тело запроса. Обратите внимание, что значения параметров обязательно должны быть закодированы в формате URL (все спецсимволы, пробелы и кириллица должны заменяться на их шестнадцатеричные коды).
// Для простоты примера предполагаем, что логин и пароль содержат только латиницу и цифры
ТелоЗапроса = "username=" + Логин + "&password=" + Пароль + "&CSRF=" + КодироватьСтроку(ТокенCSRF, СпособКодированияСтроки.КодироватьИменаКомпьютеров) + "&login=Войти";
WinHttp.Open("POST", АдресОбработчикаФормы, Ложь);
WinHttp.SetRequestHeader("Content-Type", "application/x-www-form-urlencoded");
WinHttp.SetRequestHeader("User-Agent", "Mozilla/5.0");
WinHttp.Send(ТелоЗапроса);
Шаг 5. Обработка редиректа и переход на целевой сайт
Поскольку при успешной авторизации сервер Keycloak возвращает статус перенаправления 302 Found, нам необходимо прочесть заголовок Location, в котором будет содержаться ссылка с кодом авторизации, ведущая обратно на наш целевой сайт nsddata.ru.
Если WinHttp.Status = 302 Тогда
// Получаем адрес перенаправления, содержащий временный авторизационный код (code)
АдресПерехода = WinHttp.GetResponseHeader("Location");
// Переходим по этой ссылке, чтобы целевой сайт зафиксировал успешный вход и выдал свои рабочие сессионные куки
WinHttp.Open("GET", АдресПерехода, Ложь);
WinHttp.Send();
Если WinHttp.Status = 200 Тогда
Сообщить("Авторизация успешно завершена! Сессия активна.");
Иначе
Сообщить("Не удалось подтвердить сессию на целевом сайте. Код ошибки: " + WinHttp.Status);
КонецЕсли;
Иначе
Сообщить("Авторизация отклонена сервером. Проверьте логин и пароль. Код ошибки: " + WinHttp.Status);
КонецЕсли;
После успешного прохождения шага 5 наш COM-объект WinHttp хранит в своей памяти все куки авторизованного сеанса. Теперь мы можем выполнять любые GET и POST-запросы к страницам сайта nsddata.ru для парсинга таблиц, скачивания файлов отчетов или получения JSON-данных.
Пример получения защищенной страницы после авторизации:
АдресДанных = "https://nsddata.ru/ru/personal/cabinet/some_data_page";
WinHttp.Open("GET", АдресДанных, Ложь);
WinHttp.Send();
Если WinHttp.Status = 200 Тогда
// Полученный HTML-код страницы теперь можно обрабатывать парсером в 1С
КодСтраницыДанных = WinHttp.ResponseText;
КонецЕсли;
Таким образом, мы полностью автоматизировали процесс авторизации через современную систему Keycloak на платформе 1С без использования сторонних платных сервисов и без необходимости открывать интерактивные формы входа для пользователя.