Как сохранить тип «число» в полезной нагрузке JWT токена в 1С:Предприятие

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

При интеграции 1С с современными внешними API (такими как Google API, Apple, Firebase или сервисы банков) часто требуется передавать данные в формате JWT (JSON Web Token). В платформе 1С, начиная с версии 8.3.21, появился встроенный объект ТокенДоступа, который должен упрощать эту задачу. Однако на практике разработчики сталкиваются с серьезным ограничением: при добавлении данных в ПолезнаяНагрузка (payload) числа автоматически преобразуются в строки. Для многих API это критично, так как поля exp (время истечения), iat (время выпуска) и другие должны быть строго числовыми (Unix Timestamp).

В этой статье мы подробно разберем, почему стандартный механизм ТокенДоступа может не подходить для ваших задач, и как реализовать полноценное формирование и подпись JWT токена вручную, сохранив при этом правильную типизацию данных.

Разбор проблемы: Почему ТокенДоступа подводит?

Рассмотрим стандартный код, который кажется логичным:


Токен = Новый ТокенДоступа();
Токен.ПолезнаяНагрузка.Вставить("iat", 1672531200); // Ожидаем число

При проверке такого токена на сервисах типа jwt.io мы увидим, что число превратилось в строку: "iat": "1672531200". Платформа 1С при сериализации объекта во внутренний JSON выполняет неявное приведение типов. Если принимающая сторона (API) ожидает строго integer, авторизация будет отклонена с ошибкой формата. Кроме того, при работе с большими числами (больше 999) платформа может добавить неразрывные пробелы как разделители триад, что окончательно ломает структуру токена.

Решение проблемы: Ручное формирование JWT

Чтобы полностью контролировать структуру и типы данных в токене, нам придется пройти путь формирования JWT самостоятельно. Напомним, что JWT состоит из трех частей, разделенных точкой: Header.Payload.Signature.

Проанализируем пошаговый алгоритм реализации этой задачи в среде Windows.

Шаг 1. Подготовка заголовка и полезной нагрузки

Вместо использования объекта ТокенДоступа, сформируем JSON-строки самостоятельно. Мы можем использовать объект ЗаписьJSON, который позволяет точно управлять форматом вывода.


// 1. Формируем Заголовок (Header)
ЗаголовокСтруктура = Новый Структура();
ЗаголовокСтруктура.Вставить("alg", "RS256");
ЗаголовокСтруктура.Вставить("typ", "JWT");

ЗаписьJSON = Новый ЗаписьJSON();
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(,,, ЭлементыРазделенияСтрокJSON.Нет);
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьJSON, ЗаголовокСтруктура);
СтрокаЗаголовка = ЗаписьJSON.Закрыть();

// 2. Формируем Полезную нагрузку (Payload)
НагрузкаСтруктура = Новый Структура();
НагрузкаСтруктура.Вставить("iat", 1704067200); // Теперь это гарантированно число
НагрузкаСтруктура.Вставить("iss", "my-service-account");

ЗаписьJSON = Новый ЗаписьJSON();
ЗаписьJSON.УстановитьСтроку(ПараметрыЗаписи);
ЗаписатьJSON(ЗаписьJSON, НагрузкаСтруктура);
СтрокаНагрузки = ЗаписьJSON.Закрыть();

Шаг 2. Кодирование в Base64URL

Стандарт JWT требует использования кодировки Base64URL. Она отличается от обычной Base64 тем, что символы + заменяются на -, / на _, а символы заполнения = удаляются.

В современных версиях 1С (8.3.16+) мы можем использовать встроенный метод КодированиеДанных.Base64URL. Если же ваша версия старше или вы хотите реализовать это вручную для полного контроля, используем следующий подход:


Функция ЗакодироватьBase64URL(ВходнаяСтрока)
    ДвоичныеДанные = ПолучитьДвоичныеДанныеИзСтроки(ВходнаяСтрока);
    Результат = Base64Строка(ДвоичныеДанные);
    
    // Преобразование в формат URL
    Результат = СтрЗаменить(Результат, "+", "-");
    Результат = СтрЗаменить(Результат, "/", "_");
    Результат = СтрЗаменить(Результат, "=", "");
    
    // Удаление спецсимволов переноса строки
    Результат = СтрЗаменить(Результат, Символы.ВК, "");
    Результат = СтрЗаменить(Результат, Символы.ПС, "");
    
    Возврат Результат;
КонецФункции

Часть1 = ЗакодироватьBase64URL(СтрокаЗаголовка);
Часть2 = ЗакодироватьBase64URL(СтрокаНагрузки);
ИтоговаяСтрокаДляПодписи = Часть1 + "." + Часть2;

Шаг 3. Создание цифровой подписи (RS256)

Это самый сложный этап. Для алгоритма RS256 нам нужно создать хеш SHA256 от строки Header.Payload и подписать его закрытым ключом RSA. В ОС Windows это удобно сделать через COM-объект System.Security.Cryptography.RSACryptoServiceProvider из состава .NET Framework.

Важно: Закрытый ключ должен быть в формате XML. Если ваш ключ в формате .pem, его предварительно нужно конвертировать в XML-структуру, которую понимает .NET.


// Инициализируем криптопровайдер
RSACSP = Новый COMОбъект("System.Security.Cryptography.RSACryptoServiceProvider");
RSACSP.FromXmlString(ЗакрытыйКлючXML); 

// Вычисляем хеш
Хеширование = Новый ХешированиеДанных(ХешФункция.SHA256);
Хеширование.Добавить(ИтоговаяСтрокаДляПодписи);
ХешСумма = Хеширование.ХешСумма;

// Подписываем хеш. Обратите внимание, что мы передаем бинарные данные хеша
// В 1С для передачи в COM-объект удобно использовать ADODB.Stream
ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
ХешСумма.Записать(ИмяВременногоФайла);

Поток = Новый COMОбъект("ADODB.Stream");
Поток.Open();
Поток.Type = 1; // Binary
Поток.LoadFromFile(ИмяВременногоФайла);
ДвоичныеДанныеХеша = Поток.Read(-1);
Поток.Close();

// Формируем подпись
ПодписьДвоичныеДанные = RSACSP.SignHash(ДвоичныеДанныеХеша, "SHA256");

// Сохраняем результат подписи обратно в ДвоичныеДанные 1С
Поток.Open();
Поток.Write(ПодписьДвоичныеДанные);
Поток.SaveToFile(ИмяВременногоФайла, 2); // Overwrite
Поток.Close();

ДвоичныеДанныеПодписи = Новый ДвоичныеДанные(ИмяВременногоФайла);
УдалитьФайлы(ИмяВременногоФайла);

// Кодируем подпись в Base64URL
Часть3 = ЗакодироватьBase64URL(ДвоичныеДанныеПодписи); // Используем перегрузку функции для ДД

ИтоговыйТокен = ИтоговаяСтрокаДляПодписи + "." + Часть3;

Особенности работы на разных операционных системах

Проанализируем ситуацию, если ваш сервер 1С работает на Linux. В этом случае COM-объекты (такие как RSACryptoServiceProvider или ADODB.Stream) будут недоступны. Для решения этой задачи на Linux рекомендуется:

  1. Использовать стандартный объект 1С МенеджерКриптографии. Он требует установленного в системе криптопровайдера, например, OpenSSL.
  2. Вызывать внешнюю утилиту OpenSSL через команду ЗапуститьПриложение.
  3. Использовать специализированные Native-компоненты, написанные на C++, которые предоставляют интерфейс для работы с RSA.

Важные рекомендации по работе с JSON

При формировании JSON вручную (как мы делали в Шаге 1) следует помнить о нескольких нюансах:

Таким образом, мы выяснили причину проблемы с типами данных в объекте ТокенДоступа и рассмотрели надежный способ создания JWT токена "с нуля". Использование ручного формирования JSON в сочетании с системными средствами криптографии позволяет создавать токены, полностью соответствующие международным стандартам и требованиям любых внешних API.

← На главную