При разработке интеграционных решений на базе платформы 1С часто возникает задача разграничения доступа к данным: веб-сервисом пользуются разные внешние клиенты (покупатели, партнеры, сторонние системы), и каждому из них необходимо возвращать строго их собственный набор данных (например, заказы, взаиморасчеты или номенклатуру). Разберем, как правильно организовать прикладную авторизацию и передачу ключей доступа (API-key, токенов сессий) в сервисах 1С.
В веб-сервисах на базе протокола SOAP (объект метаданных Web-сервисы) разработчики часто пытаются использовать стандартные HTTP-заголовки или SOAP Headers для передачи токенов. Однако платформа 1С имеет жесткое архитектурное ограничение:
В модуле Web-сервиса нет прямого доступа к контексту HTTP-запроса и заголовкам. Платформа самостоятельно разбирает SOAP-конверт и передает в функцию модуля исключительно те параметры, которые описаны в свойствах соответствующей операции Web-сервиса или в связанном XDTO-пакете.
Если интеграция жестко привязана к протоколу SOAP, единственным стандартным способом передачи авторизационных данных является явное добавление параметра в сигнатуру функций.
Разберем по шагам схему реализации:
default.vrd на веб-сервере прописывается единый технический пользователь 1С с минимально необходимыми правами.КлючДоступа или Token) типа string (http://www.w3.org/2001/XMLSchema).КлючиДоступаAPI) с измерениями Ключ (Строка) и ресурсами Контрагент (СправочникСсылка.Контрагенты), ДействуетДо (Дата), Заблокирован (Булево).Посмотрим на пример реализации серверной функции проверки и выборки данных:
Функция ПолучитьСписокЗаказов(КлючДоступа) Экспорт
Контрагент = ПолучитьКонтрагентаПоКлючу(КлючДоступа);
Если Контрагент = Неопределено Тогда
ВызватьИсключение "Ошибка авторизации: неверный или недействительный API-ключ";
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказПокупателя.Ссылка КАК Заказ,
| ЗаказПокупателя.Номер КАК Номер,
| ЗаказПокупателя.Дата КАК Дата,
| ЗаказПокупателя.СуммаДокумента КАК Сумма
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя
|ГДЕ
| ЗаказПокупателя.Контрагент = &Контрагент
| И НЕ ЗаказПокупателя.ПометкаУдаления";
Запрос.УстановитьПараметр("Контрагент", Контрагент);
ТаблицаДанных = Запрос.Выполнить().Выгрузить();
// Формирование и возврат сериализованного ответа (XDTO или JSON)
Возврат СериализоватьРезультат(ТаблицаДанных);
КонецФункции
Функция ПолучитьКонтрагентаПоКлючу(Знач КлючДоступа)
Если ПустаяСтрока(КлючДоступа) Тогда
Возврат Неопределено;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| КлючиДоступаAPI.Контрагент КАК Контрагент
|ИЗ
| РегистрСведений.КлючиДоступаAPI КАК КлючиДоступаAPI
|ГДЕ
| КлючиДоступаAPI.Ключ = &Ключ
| И КлючиДоступаAPI.Заблокирован = ЛОЖЬ
| И (КлючиДоступаAPI.ДействуетДо >= &ТекущаяДата ИЛИ КлючиДоступаAPI.ДействуетДо = ДАТАВРЕМЯ(1, 1, 1))";
Запрос.УстановитьПараметр("Ключ", КлючДоступа);
Запрос.УстановитьПараметр("ТекущаяДата", ТекущаяДатаСеанса());
Выборка = Запрос.Выполнить().Выбрать();
Если Выборка.Следующий() Тогда
Возврат Выборка.Контрагент;
КонецЕсли;
Возврат Неопределено;
КонецФункции
Если выбор протокола не ограничен требованиями сторонней системы, наиболее гибким и современным решением является использование объекта метаданных HTTP-сервисы вместо Web-сервисы.
Преимущество HTTP-сервисов заключается в наличии объекта HTTPСервисЗапрос, который предоставляет прямой доступ ко всем входящим HTTP-заголовкам через свойство Заголовки. Это позволяет клиентам передавать ключ в стандартных заголовках, таких как Authorization: Bearer <token> или X-API-Key, не засоряя тело запроса или параметры URL.
Рассмотрим пример чтения заголовка в обработчике метода HTTP-сервиса:
Функция ЗаказыGET(Запрос)
// Извлекаем токен из заголовков запроса
APIKey = "";
Если Запрос.Заголовки.Свойство("X-API-Key") Тогда
APIKey = Запрос.Заголовки["X-API-Key"];
ИначеЕсли Запрос.Заголовки.Свойство("authorization") Тогда
APIKey = СтрЗаменить(Запрос.Заголовки["authorization"], "Bearer ", "");
КонецЕсли;
Контрагент = ПолучитьКонтрагентаПоКлючу(APIKey);
Если Контрагент = Неопределено Тогда
Ответ = Новый HTTPСервисОтвет(401);
Ответ.УстановитьТелоИзСтроки("{""error"": ""Не авторизован""}", "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Возврат Ответ;
КонецЕсли;
// Формирование успешного ответа
СтрокаJSON = ПолучитьДанныеКонтрагентаJSON(Контрагент);
Ответ = Новый HTTPСервисОтвет(200);
Ответ.УстановитьТелоИзСтроки(СтрокаJSON, "UTF-8", ИспользованиеByteOrderMark.НеИспользовать);
Ответ.Заголовки.Вставить("Content-Type", "application/json; charset=utf-8");
Возврат Ответ;
КонецФункции
Если в конфигурации используется Библиотека стандартных подсистем (БСП), задачу можно решить на уровне системных прав:
Внешние пользователи в настройках БСП.Контрагенты.RLS), где условие фильтрации документов строится по текущему внешнему пользователю.Проанализировав возможности платформы 1С, выделим главные правила построения сервисов:
X-API-Key, Authorization) следует использовать HTTP-сервисы.