При интеграции 1С с внешними веб-сервисами (REST API, государственные информационные системы, сайты поставщиков) разработчики часто сталкиваются с требованием использовать авторизацию методом Basic Authentication (базовая аутентификация). Разберем подробно, что представляет собой этот метод, как правильно передать учетные данные из 1С и как избежать распространенных ошибок при отправке HTTP-запросов.
Метод Basic Authentication — это стандартный протокол авторизации, при котором логин и пароль пользователя передаются в заголовке HTTP-запроса. С технической точки зрения учетные данные объединяются в строку вида Логин:Пароль, кодируются по алгоритму Base64 и отправляются в заголовке запроса под названием Authorization со значением Basic [закодированная_строка].
В платформе 1С:Предприятие реализовано два основных способа работы с такой авторизацией: автоматический (через встроенные параметры объекта HTTPСоединение) и ручной (через самостоятельное формирование заголовков запроса). Ниже мы пошагово разберем оба варианта.
Самый простой и правильный способ пройти базовую авторизацию — передать логин и пароль непосредственно в конструктор объекта HTTPСоединение. Платформа 1С самостоятельно закодирует эти данные в формат Base64 и добавит необходимые заголовки к каждому запросу.
Проанализируем ситуацию, с которой столкнулся автор темы. При попытке отправить обычный запрос сервер вернул перенаправление (редирект) с сообщением "Объект перемещен" и ссылкой на защищенный протокол HTTPS. В современном веб-пространстве базовая авторизация без шифрования (по протоколу HTTP) практически не используется, так как пароли в формате Base64 легко перехватить. Поэтому для работы всегда требуется использовать защищенное SSL-соединение.
Рассмотрим пример готового и исправленного кода для отправки запроса с авторизацией по протоколу HTTPS:
// 1. Определяем параметры подключения и авторизации
Сервер = "benzindex.ru";
Логин = "ВашЛогин";
Пароль = "ВашПароль";
ПутьЗапроса = "/BenzindexAPI/api/Transactions?FromDate=2016-01-01&ToDate=2016-02-01";
// 2. Настраиваем заголовки запроса
Заголовки = Новый Соответствие();
Заголовки.Вставить("Accept", "application/json");
// 3. Создаем защищенное соединение SSL
ЗащищенноеСоединение = Новый ЗащищенноеСоединениеOpenSSL();
// 4. Инициализируем HTTP-соединение с передачей логина и пароля
HTTPСоединение = Новый HTTPСоединение(Сервер, , Логин, Пароль, , , ЗащищенноеСоединение);
// 5. Формируем запрос
HTTPЗапрос = Новый HTTPЗапрос(ПутьЗапроса, Заголовки);
// 6. Отправляем запрос и получаем ответ
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
// Выводим результат в консоль
Если HTTPОтвет.КодСостояния = 200 Тогда
ТекстОтвета = HTTPОтвет.ПолучитьТелоКакСтроку();
Сообщить(ТекстОтвета);
Иначе
Сообщить("Ошибка запроса! Код состояния: " + HTTPОтвет.КодСостояния);
КонецЕсли;
Обратим внимание на критическую ошибку, которую часто совершают разработчики (она же присутствует в сообщениях автора темы). В итоговом коде темы автор написал следующее:
HTTPЗапрос = Новый HTTPЗапрос(URL, ЗаголовокGET);
HTTPОтвет = HTTPСоединение.Получить(URL, ФайлXML); // ОШИБКА!
Выясним причину, почему этот код работает некорректно. Метод Получить объекта HTTPСоединение имеет несколько перегрузок. Передавая в качестве первого параметра строковую переменную URL вместо объекта HTTPЗапрос, мы заставляем платформу использовать устаревший синтаксис. При этом созданный ранее объект HTTPЗапрос (вместе со всеми его заголовками, включая Accept) полностью игнорируется. Сервер не получает информацию о том, что клиент ожидает ответ в формате JSON, и может вернуть ошибку или неверный формат данных.
Правило: Всегда передавайте объект HTTPЗапрос первым параметром в методы отправки (Получить, ОтправитьДляОбработки, ВызватьHTTPМетод):
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос, ПутьКФайлу);
В коде из обсуждения ответ сервера сначала записывается во временный файл на диске компьютера, а затем считывается через объект ТекстовыйДокумент. Запись на диск — это медленная операция, которая снижает производительность системы и может приводить к ошибкам прав доступа в серверных сценариях.
Современные версии платформы 1С:Предприятие 8.3 позволяют получать тело ответа напрямую в оперативную память. Для этого достаточно не указывать имя файла при вызове метода Получить(), а затем использовать метод ПолучитьТелоКакСтроку() у объекта HTTPОтвет. Платформа автоматически определит кодировку текста (например, UTF-8) на основе заголовков сервера и вернет готовую строку без "кракозябр".
Иногда стандартный механизм авторизации через конструктор HTTPСоединение может конфликтовать со специфическими прокси-серверами или нестандартными настройками веб-сервера. В таких случаях мы можем сформировать заголовок авторизации вручную.
Посмотрим на пример реализации ручной авторизации:
// 1. Формируем строку учетных данных
СтрокаАвторизации = Логин + ":" + Пароль;
// 2. Кодируем строку в формат Base64
ДвоичныеДанныеСтроки = ПолучитьДвоичныеДанныеИзСтроки(СтрокаАвторизации, КодировкаТекста.UTF8, Ложь);
ТокенBase64 = ПолучитьBase64СтрокуИзДвоичныхДанных(ДвоичныеДанныеСтроки);
// 3. Заполняем заголовки запроса вручную
Заголовки = Новый Соответствие();
Заголовки.Вставить("Authorization", "Basic " + ТокенBase64);
Заголовки.Вставить("Accept", "application/json");
// 4. Подключаемся БЕЗ указания логина и пароля в соединении
HTTPСоединение = Новый HTTPСоединение(Сервер, , , , , , Новый ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос = Новый HTTPЗапрос(ПутьЗапроса, Заголовки);
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
Этот способ дает полный контроль над передаваемыми данными и часто выручает при решении нестандартных задач интеграции.
В ходе обсуждения на форуме сервер перенаправил запрос с HTTP на версию HTTPS (код состояния 302). Платформа 1С:Предприятие по умолчанию не умеет автоматически переходить по редиректам. Если сервер возвращает код состояния из диапазона 300-399, запрос просто завершится без получения целевых данных.
Если адрес целевого ресурса может динамически меняться, нам необходимо программно обрабатывать такие ситуации. Для этого анализируют код ответа и получают новый адрес из заголовка Location:
HTTPОтвет = HTTPСоединение.Получить(HTTPЗапрос);
Если HTTPОтвет.КодСостояния >= 300 И HTTPОтвет.КодСостояния <= 399 Тогда
НовыйАдрес = HTTPОтвет.Заголовки.Получить("Location");
Если ЗначениеЗаполнено(НовыйАдрес) Тогда
Сообщить("Ресурс перемещен. Новый адрес: " + НовыйАдрес);
// Здесь должна быть логика создания нового соединения по новому адресу
КонецЕсли;
КонецЕсли;