В данную статью собраны некоторые разрозненные материалы, так или иначе связанные с http-сервисами, и не вошедшие в первую часть. Мы рассмотрим вопросы аутентификации, публикации ИБ и работы с JWT токенами.
Содержание
Варианты аутентификации для HTTP-сервисов в 1С
При работе с HTTP используются преимущественно аутентификация по логину и паролю базы 1С, либо аутентификация операционной системы. Но начиная с версии 8.3.21 в 1С появилась возможность авторизации с помощью JWT-токенов. Кроме того, доступны еще варианты аутентификации OpenID и OpenID Connect, но они используются значительно реже.
В зависимости от используемых вариантов аутентификации, при публикации базы на веб-сервере может понадобиться опубликовать ИБ несколько раз – с разными настройками аутентификации.
Рассмотрим такой пример. Пользователи ИБ, работая в домене Active Directory, должны входить в веб-клиент 1С без указания логина и пароля, используя аутентификацию ОС. В то же время некоторые сервисы должны запускаться от имени одной учетной записи AD, но под разными пользователями 1С. В этом случае нам понадобятся одновременно публикация ИБ с доменной аутентификацией и еще одна публикация – с обычной аутентификацией по логину и паролю.
Некоторые моменты касательно публикации ИБ на веб-сервере
Одна и та же база может быть опубликована несколько раз, в том числе и на разных веб-серверах. Бывает необходимость опубликовать базы, которые работают на разных версиях платформы. Для этого в IIS нужно создать отдельный пул приложений. С Apache несколько по-другому – для каждой версии платформы проще всего поднять свой собственный веб-сервер, и настроить их на разные порты.
Рассмотрим вариант публикации для двух версий платформы на примере веб-сервера IIS. Предположим, у нас есть база demohttp, использующая платформу 8.3.22 и база soap на платформе 8.3.18. Публикуем каждую базу как обычно, средствами конфигуратора. Далее нам понадобится запустить диспетчер служб IIS и настроить пулы приложений – на каждую версию платформы понадобится отдельный пул приложений. У нас уже будет один пул по умолчанию – DefaultAppPool. Добавим еще один и назовем его понятным образом. Например для платформы 8.3.18 пул может называться 8318.
Далее нам нужно зайти в основные настройки опубликованного приложения, в нашем случае – “soap”, и выбрать нужный пул.
Важно! В случае переопубликации этого приложения пул снова будет заменен на основной по умолчанию. В этом случае нужно будет повторить связку приложения с пулом. Либо вместо публикации средствами конфигуратора нужно будет вручную скорректировать файлы публикации на веб-сервере.
Настройка файла default.vrd
Подробно формат файла default.vrd описан в документации по платформе, в руководстве администратора, нас же интересует секция описания веб-сервисов.
Данный файл содержит в себе все настройки публикации конкретной базы. Например, в одной публикации мы можем разместить только доступ для пользователей через тонкий и веб-клиенты, а в другой – только для http-сервисов, и т.п. Файл default.vrd можно модифицировать вручную любым текстовым редактором, но после повторной публикации средствами конфигуратора содержимое будет заменено.
Именно поэтому бывает удобнее вручную скорректировать файл, например, добавить описание http-сервиса, чем публиковать через конфигуратор и потом все перенастраивать.
Рассмотрим секцию httpServices. Она состоит из элементов Service, каждый из которых и описывает отдельный сервис. Настройки сервиса в конфигураторе практически соответствуют, за исключением размера пула соединений poolSize и таймаута ожидания poolTimeout. Данные свойства используются при управлении переиспользованием соединений в автоматическом режиме.
<httpServices> <service name="HelloWorld" rootUrl="helloworld" enable="true" reuseSessions="autouse" sessionMaxAge="2" poolSize="10" poolTimeout="5"/> </httpServices>
Соответственно, если нам нужно добавить еще один сервис в уже опубликованную базу, это можно сделать, отредактировав файл default.vrd и добавив еще одну секцию.
Важно! Средствами конфигуратора нельзя задать размер пула и время ожидания, поэтому не рекомендуется переопубликовывать ИБ на веб-сервере средствами конфигуратора, если данные значения были изменены.
Выполнение http-сервисов от имени одного пользователя и анонимный доступ
Предположим, мы хотим, чтобы наш http-сервис был публичным, и не требовал от пользователя какой-либо аутентификации. Но исполнять этот веб-сервис на стороне 1С мы хотим от имени конкретного пользователя с конкретными правами. Ведь если делать базу без пользователей – автоматически у всех будет полный доступ к ней. А если есть пользователи – то не получится войти в базу анонимно.
В этом случае решение, пусть и не самое элегантное – указать конкретного пользователя в настройках опубликованной базы в файле default.vrd, для корневого узла point. Для этого в свойстве ib необходимо добавить атрибуты Usr и Pwd.
<point xmlns="http://v8.1c.ru/8.2/virtual-resource-system" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" base="/demohttp" ib="File="E:\alexcode уроки youtube";Usr="notAdmin";Pwd="strongPassword";">
Работа с JWT-токенами
Авторизация при помощи JWT токенов в 1С появилась не так давно. Тем не менее, и до того как это появилось в платформе, можно было реализовать аутентификацию с использованием JWT, но для этого понадобится написать достаточно много кода. Ознакомиться с подобным решением можно по ссылке: https://github.com/pintov/1c-jwt
Мы рассмотрим как вариант авторизации средствами платформы, так и более экзотический сценарий, когда передается токен внешней системы (например, Azure Active Directory). В первом случае нам достаточно передавать токен в заголовках http-запроса либо в параметрах запроса в адресной строке. Все остальное на себя возьмет платформа.
Второй случай может понадобиться, если мы хотим использовать сервис 1С в качестве промежуточного, например сформировать какие-то данные на стороне 1С, проанализировав внешний токен, и затем вызвать следующий сервис по цепочке.
Создание JWT-токена
JWT-токен состоит из трех частей – заголовка, полезной нагрузки и подписи. Все это кодируется в формат Base64URL. Посмотреть на расшифровку токена можно, например здесь: https://jwt.io/
Для того чтобы средствами языка 1С сгенерировать корректный токен, начиная с версии 8.3.21 можно использовать объект ТокенДоступа. Рассмотрим пример генерации jwt токена:
АлгоритмПодписи = АлгоритмПодписиТокенаДоступа.HS256; ТокенДоступа = Новый ТокенДоступа; ТокенДоступа.Заголовки.Вставить("alg", Строка(АлгоритмПодписи)); ТокенДоступа.Эмитент = "ssl"; // на момент публикации указание других эмитентов делает токен нерабочим МассивПолучателей = Новый Массив; МассивПолучателей.Добавить("testjwt"); // имя http-сервиса из default.vrd ТокенДоступа.Получатели = МассивПолучателей; ТокенДоступа.КлючСопоставленияПользователя = "admin"; //Имя пользователя ИБ строкой //Один из вариантов получения времени UTC ТокенДоступа.ВремяСоздания = Дата(1,1,1) + ТекущаяУниверсальнаяДатаВМиллисекундах()/1000 - Дата(1970,1,1,1,0,0);; ТокенДоступа.ВремяЖизни = 31536000; ТокенДоступа.Идентификатор = Новый УникальныйИдентификатор; //вторым параметром нужно указать строку в Base64 кодировке. Можно сгенерировать ее сторонним сервисом или средствами 1С ТокенДоступа.Подписать(АлгоритмПодписи, Base64Строка(ПолучитьДвоичныеДанныеИзСтроки("Секретный ключ нужно прописать в vrd"))); Токен = Строка(ТокенДоступа); // при получении токена строкой он автоматически преобразуется в Base64Url
Авторизация при помощи JWT-токена
Чтобы HTTP сервис заработал с авторизацией по JWT токену, понадобится внести изменения в файл default.vrd, а именно – добавить секцию accessTokenAuthentication. Кроме того, у пользователя ИБ в 1С, от имени которого будет выполняться сервис, должна быть включена аутентификация токеном доступа. Все остальное платформа берет на себя.
Рассмотрим текст секции accessTokenAuthentication для приведенного выше примера генерации токена:
<accessTokenRecepientName>testjwt</accessTokenRecepientName> <issuers> <issuer name="ssl" authenticationClaimName="sub" authenticationUserPropertyName="name" keyInformation="0KHQtdC60YDQtdGC0L3Ri9C5INC60LvRjtGHINC90YPQttC90L4g0L/RgNC+0L/QuNGB0LDRgtGMINCyIHZyZA=="/> </issuers> </accessTokenAuthentication>
issuer name будет “ssl” – то же что в поле Эмитент при генерации токена, keyInformation – это Base64 закодированный секретный ключ, accessTokenRecepientName – имя HTTP сервиса, для которого мы производим настройку. Соответственно, для разных сервисов секретные ключи могут быть разные.
В заголовках при вызове сервиса необходимо будет передавать заголовок Authorization: с токеном Bearer текстТокена, например:
Запрос = Новый HTTPЗапрос("/get"); Запрос.Заголовки.Вставить("Authorization", "Bearer " + ТекстТокена);
Также можно передать параметр запроса …/testjwt?AccessToken=текстТокена
Разбор JWT-токена
Аутентификация JWTтокенами в 1С возможна только теми токенами, которые сгенерированы по определенному формату. При этом различные внешние системы могут предоставлять свои собственные токены, которые нельзя будет использовать для авторизации средствами платформы, но можно проанализировать их содержимое, проделать какие-то манипуляции на стороне 1С, и передать дальше. Либо написать код, который будет являться аналогом авторизации по внешнему токену. В этом случае нам понадобится расшифровать токен для дальнейшего анализа.
Есть множество сервисов для декодирования JWT токенов, например jwt.io или jwt.ms, они могут пригодиться для проверки расшифровки, полученной средствами языка 1С.
Рассмотрим код, разбирающий текст токена на заголовок, содержимое и подпись. Сперва мы разделяем текст по точкам на три части. Далее заголовок и содержимое мы можем декодировать, сперва получив двоичные данные из Base64Url строки, а затем получив строку из этих двоичных данных. Подпись мы расшифровать не можем, в разных приложениях она формируется по-разному. В 1С она генерируется следующим образом: через точку соединяется заголовок, содержимое и секретный ключ в Base64, а после полученная строка шифруется алгоритмом HMACSHA256.
&НаСервере Процедура РазобратьJWTНаСервере() //JWT представляет собой base64-закодированный JSON, состоящий из трех частей, разделенных точкой. МассивЧастей = СтрРазделить(Токен, "."); Заголовок64 = МассивЧастей[0]; Содержимое64 = МассивЧастей[1]; Подпись = МассивЧастей[2]; ЭлементыТокена = СтрРазделить(Токен, "."); Если ЭлементыТокена.Count() <> 3 Тогда Возврат; КонецЕсли; Содержимое64 = ЭлементыТокена[1]; ЗаголовокСтрока = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанныеЭлементаТокенаJWT(Заголовок64)); Содержимое = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанныеЭлементаТокенаJWT(Содержимое64)); ЧтениеJSON = Новый ЧтениеJSON; ЧтениеJSON.УстановитьСтроку(Содержимое); СодержимоеСтруктура = ПрочитатьJSON(ЧтениеJSON); КонецПроцедуры &НаСервере Функция ДвоичныеДанныеЭлементаТокенаJWT(Знач Значение) Значение = СтрЗаменить(Значение, "-", "+"); Значение = СтрЗаменить(Значение, "_", "/"); Остаток = СтрДлина(Значение) % 4; Если Остаток = 1 Тогда Возврат Неопределено; ИначеЕсли Остаток = 2 Тогда Значение = Значение + "=="; ИначеЕсли Остаток = 3 Тогда Значение = Значение + "="; КонецЕсли; Возврат Base64Значение(Значение); КонецФункции
Получим следующий результат:
Заголовок
{ "alg": "HS256", "typ": "JWT" }
Содержимое
{ "jti": "7e431e97-4b83-48e2-b455-8ec1de29d85a", "exp": "1708847434.64", "aud": "testjwt", "sub": "admin", "nbf": "1677311434.64", "iat": "1677311434.64", "iss": "ssl" }
Подпись
36uAblV0Yfx9uoyZekeSs25E12XWeqr1KmKFhWRzwv0
Очень полезная статья