Челленджи интеграции Azure BlobStorage с Salesforce Commerce Cloud

Підписуйтеся на Telegram-канал «DOU #tech», щоб не пропустити нові технічні статті.

Всем привет. Меня зовут Иван Стариков, три года я работаю с платформой электронной коммерции Salesforce Commerce Cloud (далее SFCC, кратко о платформе можно почитать в этой статье), в роли веб-разработчика в компании Astound Commerce. За время работы пришлось работать с разными 3rd-party сервисами, интегрировать их. Это были различные службы доставки, платежные методы, поиск адресов и т.п. Некоторые интеграции вполне тривиальны, «обкатаны», но некоторые отличаются тем, что приходится быть первопроходцем. В этой статье хочу рассказать как раз о такой интеграции. Статья будет интересна разработчикам в срезе разных подходов к интеграции сервиса облачного хранения Azure, а также непосредственно SFCC-разработчикам.

Постановка задачи

Мы получили запрос от клиента, чтобы организовать внешнее хранилище данных для хранения файлов пользователя, а именно речь идет о хранении изображений для персонализации продукта пользователем.

Ограничения платформы SFCC

Платформа SFCC не подразумевает хранилища для файлов, доступных извне. Естественно файловое хранилище существует, но целенаправленно используется для «внутренних» нужд системы. Оно ограничено по размерам, производительности и, главное, — безопасности. Доступа извне к этому хранилищу нет. То есть, например, мы можем записать файл из контроллера, но чтобы прочитать этот файл или отобразить на клиентской стороне — нам придется в ручном режиме возвращать файл, что ресурсозатратно (дополнительный вызов на бекенд), неоптимально и затратно по времени.

Изображение 1. Пример структуры каталога Impex

Обоснование решения

Принимая во внимание требования к возможности персонализации продуктов — изображение должно быть загружено/отображено буквально сразу. И у пользователя должна быть возможность загрузить разные изображения, «примерить» их, и выбрать, что же в итоге будет по нраву.

Ввиду вышеописанных ограничений, было принято решение использовать облачное хранилище. У клиента выбор пал на Microsoft Azure, поскольку проще расширить существующую подписку, чем открывать новую.

Разбираемся с Azure SDK

Начинать интеграцию лучше с ознакомления с официальной документацией и SDK

Изображение 2. Azure SDK for JS

SDK состоит из 2х частей — клиентской и серверной. В нашем случае серверной частью воспользоваться не удастся, потому что она рассчитана на запуск в среде Node.JS. Серверная часть SFCC хоть и понимает JS (ECMAScript 5), но не позволяет запускать NodeJS модули.

Стандартным решением проблемы в таком случае является создание Сервиса для общения с Azure API.

Изображение 3. Пример сервиса для взаимодействия с Azure API

И вот тут стоит остановиться подробнее на самом Azure и методах взаимодействия с ним.

Документация описывает несколько вариантов аутентификации. В нашем случае решение будет основано на Blob Storage (Azure Blobs на скриншоте).

Изображение 4. Типы облачного хранилища Azure

Выбор из доступных вариантов аутентификации

Есть следующие варианты авторизации:

  • Shared Key — авторизация по заголовкам http-запроса
  • SAS — авторизация по специальным параметрам в url
  • Active Directory
  • Открытый доступ для чтения изображений

Последнее мы не будем рассматривать — сервера SFCC будут вне домена AD, а вариант с открытым доступом для чтения нас также не устроит ввиду конфиденциальности загружаемых изображений.

Shared Key. Алгоритм формирования подобных заголовков для авторизации хорошо задокументирован (docs.microsoft.com/...​authorize-with-shared-key).

Необходимо передать заголовок авторизации в http запросе

Authorization="[SharedKey|SharedKeyLite] <AccountName>:<Signature>"

Строка signature формируется следующим образом:

1. Сформировать строку для подписи по следующему алгоритму

StringToSign = VERB + "\n" +  
               Content-Encoding + "\n" +  
               Content-Language + "\n" +  
               Content-Length + "\n" +  
               Content-MD5 + "\n" +  
               Content-Type + "\n" +  
               Date + "\n" +  
               If-Modified-Since + "\n" +  
               If-Match + "\n" +  
               If-None-Match + "\n" +  
               If-Unmodified-Since + "\n" +  
               Range + "\n" +  
               CanonicalizedHeaders +   
               CanonicalizedResource;  

2. Закодировать ее

Signature=Base64(HMAC-SHA256(UTF8(StringToSign), Base64.decode(<your_azure_storage_account_shared_key>)))  

Всё, можем приступать — имплементация простая, обычный сервис для общения посредством REST API, создали заголовки, добавили в запрос, отправили/получили данные. Успех? В ходе разработки выясняется — есть квота (ввиду контроля производительности, в SFCC встроены ограничения на разные ресурсоемкие операции)

Quota api.dw.net.HTTPClient.send()@SF (enforced, warn 5, limit 8): limit exceeded 1 time(s), max actual was 9

Метод, используемый при отправке данных сервисом — HTTPClient.send()

В рамках одного HTTP-запроса к сервису мы ограничены отправкой 8 файлов. Хм. При этом пользователю доступна условно-неограниченная возможность загрузки изображений (несколько за раз, перезаливка и т.п.).

Хорошо, для нас есть еще один вариант авторизации.

Shared Access Signature. Это набор get-параметров с токеном доступа. Выглядит вот так:

?sv=2012-02-12&st=2009-02-09&se=2009-02-10&sr=c&sp=r&si=YWJjZGVmZw%3d%3d&sig=dD80ihBh5jfNpymO5Hg1IdiJIEvHcJpCMiCMnN%2fRnbI%3d

В SDK есть возможность использования SAS токена

Изображение 5. Описание доступа к Blob клиенту с помощью SAS токена

Таким образом, нам необходимо «пробросить» это токен с бэкенда на фронтенд, и при инициализации BlobClient использовать его.

Особенности использования SAS токенов

Например, безопасность. Нам необходимо защитить токен по ip. Нежелательно его передавать в открытом виде, ведь, перехватив его, можно как угодно управлять хранилищем (в рамках полномочий токена).

Изображение 6. Генерация SAS токена на портале Azure с привязкой к IP

Пойдем немного дальше, и имплементируем генерацию токена для каждого отдельного файла.

   var specificUriRequest = [
       X_MS_SAS_SP, // signedPermissions
       dateStart, // signedStart
       dateEnd, // signedExpiry
       canonicalizedResource + specificUri, // canonicalizedResource
       '', // signedIdentifier
       serverIp, // signedIP
       X_MS_SAS_SPR, // signedProtocol
       X_MS_VERSION, // signedVersion
       X_MS_SAS_SR, // signedResource
       '', // signedSnapshotTime
       '', // rscc
       '', // rscd
       '', // rsce
       '', // rscl
       '' // rsct
   ];
 
   var stringToSignUri = specificUriRequest.map(function (el) {
       return (StringUtils.trim(el));
   }).join('\n');
 
   var signatureBytesUri = mac.digest(stringToSignUri, Encoding.fromBase64(azureKey));
   var signatureEncodedUri = Encoding.toBase64(signatureBytesUri);

Фрагмент кода 1. Генерация токена для доступа к конкретному файлу

Таким образом, даже если токен и будет перехвачен, то его TTL ограничено, и он может быть использован лишь для доступа к конкретному файлу, и снова-таки ограничение использования по IP.

Токен формируем при загрузке изображения и далее уже его используем для доступа со стороны клиентской части.

Что можно было улучшить?

Рассматривали вариант имплементации некоего подобия lazy-loader для загрузки изображений в виде base64, но ввиду снижения производительности в таком случае от этого отказались.

Также генерация токена для каждого изображения тоже не самое оптимальное решение. Как вариант, рассматривается временный токен для взаимодействия с папкой пользователя на короткий промежуток времени и с привязкой по ip.

Вместо заключения

Документация по работе с Azure достаточно обширна и хорошо расписана, но есть ряд нюансов, которые нужно просто знать. Это касается генерации токенов, для разных типов доступа — к blob-сущности, контейнеру или сервису в целом. Поэтому какое-то время пришлось затратить чтобы разобраться в этих самых нюансах.

Реализация получилась в чем-то сложнее, чем ожидалось, но достаточно стабильная и соответствующая требованиям и ожиданиям заказчика.

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

👍НравитсяПонравилось3
В избранноеВ избранном0
LinkedIn
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Допустимые теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Ват зе хек из SFCC?
Навіщо мені інтегрувати Santa Fe Community College з Азурой?

Згода, воно не треба) загалом дякую за влучне зауваження — не зазначив, що SFCC є Salesforce Commerce Cloud, платформа для електронної комерції. Загально про платформу є тут: dou.ua/forums/topic/31619

Це краще до вступу добавити, інакше виглядає як лекція по війсковій підготовці або вступу до радіо-мереж — нескінченний потік шифрів :)

Подписаться на комментарии