У государства большие планы по развитию системы маркировки товаров, в связи с этим бизнесу надо научиться взаимодействовать с системой маркировки товаров Честный знак. API описан здесь.
Основа взята из публикации //infostart.ru/public/1236219/, но в отличии от неё всё реализовано средствами 1С. В обработке реализовано получение токена с использованием электронной подписи, отправка запроса и получение ответа в файл .json
Проверено на платформе 8.3.15.1830, конфигурации Бухгалтерия предприятия 3.0.80.40. Код обработки ниже:
&НаСервере
Процедура ЗаписатьВЖурнал(Данные)
Файл = Новый ЗаписьТекста(ПутьКФайламОтветов + "log.txt",,,Истина);
Файл.ЗаписатьСтроку(Строка(ТекущаяДата()) + ": " + Данные);
Файл.Закрыть();
КонецПроцедуры
&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
//Поиск доступных сертификатов
CAPICOM_CURRENT_USER_STORE = 2;
//2 - Искать сертификат в ветке "Личное" хранилища.
CAPICOM_MY_STORE = "My";
// Указываем, что ветку "Личное" берем из хранилища текущего пользователя
CAPICOM_STORE_OPEN_READ_ONLY = 0; // Открыть хранилище только на чтение
oStore = Новый COMОбъект("CAdESCOM.Store"); // Объект описывает хранилище сертификатов
oStore.Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE,
CAPICOM_STORE_OPEN_READ_ONLY); // Открыть хранилище сертификатов
// 1 вариант: поиск сертификата по отпечатку
//CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
//Certificates = oStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, ОтпечатокСтр);
//Рез = Certificates.Item(1);
//2 вариант: обходом по коллекции и сравнение с отпечатком
Для Каждого ТекСертификат Из oStore.Certificates Цикл
НоваяСтрока = Сертификаты.Добавить();
НоваяСтрока.Владелец = ТекСертификат.SubjectName;
НоваяСтрока.ПериодС = ТекСертификат.ValidFromDate;
НоваяСтрока.ПериодДо = ТекСертификат.ValidToDate;
НоваяСтрока.Контейнер = ТекСертификат.PrivateKey.UniqueContainerName;
НоваяСтрока.Отпечаток = ТекСертификат.Thumbprint;
КонецЦикла;
//Запрос = "/api/v3/facade/identifytools/listV2?cisStatus=INTRODUCED&limit=10000";
Запрос = "/api/v3/facade/cis/cis_list?cis=010462007200949521tkHSO<.I)jqC(";
Сервер = "ismp.crpt.ru";
ПутьКФайламОтветов = "C:\temp\GISMT\";
КонецПроцедуры
&НаКлиенте
Процедура СертификатыПриАктивизацииСтроки(Элемент)
СертификатДляОбмена = Элемент.ТекущиеДанные.Отпечаток;
КонецПроцедуры
&НаКлиенте
Процедура ПолучитьТокен(Команда)
ПолучитьТокенНаСервере();
КонецПроцедуры
&НаСервере
Процедура ПолучитьТокенНаСервере()
// Получение данных для получения токена
HTTPСоединение = Новый HTTPСоединение(Сервер,443,,,,,Новый ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос = новый HTTPЗапрос("/api/v3/auth/cert/key");
HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод("GET",HTTPЗапрос);
ОтветСтрока = HTTPОтвет.ПолучитьТелоКакСтроку("UTF-8");
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(ОтветСтрока);
ДанныеJSON = ПрочитатьJSON(ЧтениеJSON);
ЧтениеJSON.Закрыть();
УИД = ДанныеJSON.uuid;
ДанныеДляПолученияТокена = ДанныеJSON.data;
ЗаписатьВЖурнал("Получение данных /api/v3/auth/cert/key" + Символы.ПС + ДанныеДляПолученияТокена);
// Подписание данных для получения токена
ДанныеДляПолученияТокена = ПодписатьТекст(ЗашифроватьBase64(ДанныеДляПолученияТокена, КодировкаТекста.UTF8),СертификатДляОбмена,Ложь);
ЗаписатьВЖурнал("Подписано сертификатом " + СертификатДляОбмена + Символы.ПС + ДанныеДляПолученияТокена);
// Получение токена с использованием подписанных данных
Соединение = Новый HTTPСоединение(Сервер,443,,,,,Новый ЗащищенноеСоединениеOpenSSL);
Заголовки = Новый Соответствие;
Заголовки.Вставить("Content-Type", "application/json; charset=UTF-8");
Заголовки.Вставить("Accept", "application/json");
HTTPЗапрос = Новый HTTPЗапрос("/api/v3/auth/cert/",Заголовки);
ЗаписьJOIN = Новый ЗаписьJSON;
ЗаписьJOIN.УстановитьСтроку();
ДанныеДляЗапроса = Новый Структура;
ДанныеДляЗапроса.Вставить("uuid",УИД);
ДанныеДляЗапроса.Вставить("data",ДанныеДляПолученияТокена);
ЗаписатьJSON(ЗаписьJOIN,ДанныеДляЗапроса);
СтрокаДляЗапроса = ЗаписьJOIN.Закрыть();
HTTPЗапрос.УстановитьТелоИзСтроки(СтрокаДляЗапроса,КодировкаТекста.UTF8, ИспользованиеByteOrderMark.НеИспользовать);
Ответ = Соединение.ОтправитьДляОбработки(HTTPЗапрос);
ЧтениеJSON = Новый ЧтениеJSON;
ЧтениеJSON.УстановитьСтроку(Ответ.ПолучитьТелоКакСтроку());
Токен = ПрочитатьJSON(ЧтениеJSON, Ложь).token;
КонецПроцедуры
&НаСервере
Функция ЗашифроватьBase64(Строка, Кодировка) Экспорт
ИмяВременногоФайла = ПолучитьИмяВременногоФайла();
ЗаписьТекста = Новый ЗаписьТекста(ИмяВременногоФайла, Кодировка);
ЗаписьТекста.Записать(Строка);
ЗаписьТекста.Закрыть();
Двоичные = Новый ДвоичныеДанные(ИмяВременногоФайла);
Результат = Base64Строка(Двоичные);
Если Лев(Результат, 4) = "77u/" Тогда
Результат = Сред(Результат, 5);
КонецЕсли;
Результат = СтрЗаменить(Результат, Символы.ПС, "");
УдалитьФайлы(ИмяВременногоФайла);
Возврат Результат;
КонецФункции
&НаСервере
// sThumbprint - отпечаток сертификата, используемого для подписи; строка,
// представляющая отпечаток в шестнадцатеричном виде
// пример 195934d72dcdf69149901d6632aca4562d8806d8
// ТекстДляПодписи должен быть в Base64
// bDetached - Истина/Ложь - откреплённая(для подписания документов)/прикреплённая(для получения токена авторизации) подпись
Функция ПодписатьТекст(ТекстДляПодписи, sThumbprint, bDetached)
CADESCOM_BASE64_TO_BINARY = 1; // Входные данные пришли в Base64
CADESCOM_CADES_TYPE = 1; // Тип усовершенствованной подписи
CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME = 0; // Атрибут штампа времени подписи
oSigner = Новый COMОбъект("CAdESCOM.CPSigner");
// Объект, задающий параметры создания и содержащий информацию об усовершенствованной подписи.
oSigner.Certificate = ПолучитьСертификатПоОтпечатку(sThumbprint);
oSigningTimeAttr = Новый COMОбъект("CAdESCOM.CPAttribute");
oSigningTimeAttr.Name = CAPICOM_AUTHENTICATED_ATTRIBUTE_SIGNING_TIME;
oSigningTimeAttr.Value = ТекущаяДата();
oSigner.AuthenticatedAttributes2.Add(oSigningTimeAttr);
ТекстДляПодписи = СокрЛП(ТекстДляПодписи);
oSignedData = Новый COMОбъект("CAdESCOM.CadesSignedData");
// Объект CadesSignedData предоставляет свойства и методы для работы с усовершенствованной подписью.
oSignedData.ContentEncoding = CADESCOM_BASE64_TO_BINARY;
oSignedData.Content = СокрЛП(ТекстДляПодписи);
EncodingType = 0;
sSignedMessage = oSignedData.SignCades(oSigner, CADESCOM_CADES_TYPE,
bDetached, EncodingType);
// Метод добавляет к сообщению усовершенствованную подпись.
Возврат sSignedMessage; // Подпись в формате Base64
КонецФункции
&НаСервере
//Отпечаток - строка HEX
Функция ПолучитьСертификатПоОтпечатку(ОтпечатокСтр)
Рез = Неопределено; // Найденный сертификат (Com-объект)
CAPICOM_CURRENT_USER_STORE = 2;
//2 - Искать сертификат в ветке "Личное" хранилища.
CAPICOM_MY_STORE = "My";
// Указываем, что ветку "Личное" берем из хранилища текущего пользователя
CAPICOM_STORE_OPEN_READ_ONLY = 0; // Открыть хранилище только на чтение
oStore = Новый COMОбъект("CAdESCOM.Store"); // Объект описывает хранилище сертификатов
oStore.Open(CAPICOM_CURRENT_USER_STORE, CAPICOM_MY_STORE,
CAPICOM_STORE_OPEN_READ_ONLY); // Открыть хранилище сертификатов
// 1 вариант: поиск сертификата по отпечатку
//CAPICOM_CERTIFICATE_FIND_SHA1_HASH = 0;
//Certificates = oStore.Certificates.Find(CAPICOM_CERTIFICATE_FIND_SHA1_HASH, ОтпечатокСтр);
//Рез = Certificates.Item(1);
//2 вариант: обходом по коллекции и сравнение с отпечатком
Для Каждого ТекСертификат Из oStore.Certificates Цикл
ТекОтпечаток = ТекСертификат.Thumbprint; // возвращается отпечаток в шестнадцатеричном виде
Если ВРЕГ(ТекОтпечаток) = ВРЕГ(ОтпечатокСтр) Тогда Рез = ТекСертификат;
Прервать;
КонецЕсли;
КонецЦикла;
oStore.Close(); // Закрыть хранилище сертификатов и освободить объект 61
Возврат Рез;
КонецФункции
&НаКлиенте
Процедура ОтправитьЗапрос(Команда)
ОтправитьЗапросНаСервере();
КонецПроцедуры
&НаСервере
Процедура ОтправитьЗапросНаСервере()
HTTPСоединение = Новый HTTPСоединение(Сервер,443,,,,,Новый ЗащищенноеСоединениеOpenSSL);
HTTPЗапрос = новый HTTPЗапрос(Запрос);
HTTPЗапрос.Заголовки.Вставить("Authorization","Bearer "+Токен);
HTTPОтвет = HTTPСоединение.ВызватьHTTPМетод("GET",HTTPЗапрос);
Сообщить(HTTPОтвет.КодСостояния);
ИмяФайлаОтвета = ПутьКФайламОтветов + Строка(Новый УникальныйИдентификатор)+".json";
HTTPОтвет.ПолучитьТелоКакДвоичныеДанные().Записать(ИмяФайлаОтвета);
ЗаписатьВЖурнал("Запрос: " + Запрос + Символы.ПС + "Ответ: " + ИмяФайлаОтвета);
КонецПроцедуры