Реализация веб-перехватчика в службе SaaS

При создании предложения SaaS для транзакций в Центре партнеров партнер предоставляет URL-адрес веб-перехватчика Подключение ion, который будет использоваться в качестве конечной точки HTTP. Этот веб-перехватчик вызывается Майкрософт с помощью HTTP-вызова POST, чтобы уведомить сторону издателя о следующих событиях, происходящих на стороне Майкрософт:

Событие веб-перехватчика 1. При получении 2. Если принято 3. Если отклонено
ChangePlan Ответ с помощью HTTP 200 PATCH с успехом (это событие является необязательным и автоматически настроено в 10 с) PATCH с ошибкой OR отвечает 4xx (в течение 10 секунд)
ChangeQuantity Ответ с помощью HTTP 200 PATCH с успехом (это событие является необязательным и автоматически настроено в 10 с) PATCH с ошибкой OR отвечает 4xx (в течение 10 секунд)
Renew Ответ с помощью HTTP 200 Неприменимо Неприменимо
Suspend Ответ с помощью HTTP 200 Неприменимо Неприменимо
Unsubscribe Ответ с помощью HTTP 200 Неприменимо Неприменимо
Reinstate Ответ с помощью HTTP 200 Нет данных Неприменимо (вызов API удаления для активации удаления, если восстановление не может быть принято)

Издатель должен реализовать веб-перехватчик в службе SaaS, чтобы обеспечить согласованный статус подписки SaaS на стороне Майкрософт. Служба SaaS требуется для вызова API-интерфейса операции Get для проверки и авторизации вызова веб-перехватчика и полезных данных перед выполнением действия с учетом данных в уведомлении веб-перехватчика. Издатель должен возвращать код HTTP 200 в Майкрософт непосредственно после обработки вызова веб-перехватчика. Это значение подтверждает, что вызов веб-перехватчика был успешно получен издателем.

Внимание

Служба URL-адреса веб-перехватчика должна быть запущена и запущена 24 x 7 и готова получать новые вызовы от Корпорации Майкрософт в любое время. Корпорация Майкрософт имеет политику повторных попыток для вызова веб-перехватчика (500 повторных попыток в течение восьми часов), но если издатель не принимает вызов и возвращает ответ, операция, о которую веб-перехватчик уведомляет о том, что в конечном итоге завершится сбоем на стороне Майкрософт.

Внимание

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

Внимание

Поставщики программного обеспечения должны проверить токен Microsoft Entra (токен JWT) в конечной точке веб-перехватчика из заголовка запроса. Это стандартный маркер носителя и предоставит поставщику программного обеспечения сведения о том, кто вызывается. Узнайте больше о том, как проверить маркер в этой статье. learn.microsoft.com/azure/active-directory/develop/access-tokens

Пример полезных данных веб-перехватчика в ChangePlan:

{
    "id": "<guid>",
    "activityId": "<guid>",
    "publisherId": "XXX",
    "offerId": "YYY",
    "planId": "plan2",
    "quantity": 10,
    "subscriptionId": "<guid>",
    "timeStamp": "2023-02-10T18:48:58.4449937Z",
    "action": "ChangePlan",
    "status": "InProgress",
    "operationRequestSource": "Azure",
    "subscription":
    {
      "id": "<guid>",
      "name": "Test",
      "publisherId": "XXX",
      "offerId": "YYY",
      "planId": "plan1",
      "quantity": 10,
      "beneficiary":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "purchaser":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "allowedCustomerOperations": ["Delete", "Update", "Read"],
      "sessionMode": "None",
      "isFreeTrial": false,
      "isTest": false,
      "sandboxType": "None",
      "saasSubscriptionStatus": "Subscribed",
      "term":
        {
          "startDate": "2022-02-10T00:00:00Z",
          "endDate": "2022-03-12T00:00:00Z",
          "termUnit": "P1M",
          "chargeDuration": null,
        },
      "autoRenew": true,
      "created": "2022-01-10T23:15:03.365988Z",
      "lastModified": "2022-02-14T20:26:04.5632549Z",
    },
    "purchaseToken": null
}

Пример полезных данных веб-перехватчика события ChangeQuantity:


{
    "id": "<guid>",
    "activityId": "<guid>",
    "publisherId": "XXX",
    "offerId": "YYY",
    "planId": "plan1",
    "quantity": 20,
    "subscriptionId": "<guid>",
    "timeStamp": "2023-02-10T18:54:00.6158973Z",
    "action": "ChangeQuantity",
    "status": "InProgress",
    "operationRequestSource": "Azure",
    "subscription": {
        "id": "<guid>",
        "name": "Test",
        "publisherId": "XXX",
        "offerId": "YYY",
        "planId": "plan1",
        "quantity": 10,
        "beneficiary":
            {
            "emailId": XX@outlook.com,
            "objectId": "<guid>",
            "tenantId": "<guid>",
            "puid": "1234567890",
            },
        "purchaser":
            {
            "emailId": XX@outlook.com,
            "objectId": "<guid>",
            "tenantId": "<guid>",
            "puid": "1234567890",
            },
        "allowedCustomerOperations": ["Delete", "Update", "Read"],
        "sessionMode": "None",
        "isFreeTrial": false,
        "isTest": false,
        "sandboxType": "None",
        "saasSubscriptionStatus": "Subscribed",
        "term":
            {
            "startDate": "2022-02-10T00:00:00Z",
            "endDate": "2022-03-12T00:00:00Z",
            "termUnit": "P1M",
            "chargeDuration": null,
            },
        "autoRenew": true,
        "created": "2022-01-10T23:15:03.365988Z",
        "lastModified": "2022-02-14T20:26:04.5632549Z",
    },
    "purchaseToken": null
}

Пример полезных данных веб-перехватчика события восстановления подписки:

// end user's payment instrument became valid again, after being suspended, and the SaaS subscription is being reinstated


{
    "id": "<guid>",
    "activityId": "<guid>",
    "publisherId": "XXX",
    "offerId": "YYY",
    "planId": "plan1",
    "quantity": 100,
    "subscriptionId": "<guid>",
    "timeStamp": "2023-02-11T11:38:10.3508619Z",
    "action": "Reinstate",
    "status": "InProgress",
    "operationRequestSource": "Azure",
    "subscription":
    {
      "id": "<guid>",
      "name": "Test",
      "publisherId": "XXX",
      "offerId": "YYY",
      "planId": "plan1",
      "quantity": 100,
      "beneficiary":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "purchaser":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "allowedCustomerOperations": ["Delete", "Update", "Read"],
      "sessionMode": "None",
      "isFreeTrial": false,
      "isTest": false,
      "sandboxType": "None",
      "saasSubscriptionStatus": "Suspended",
      "term":
        {
          "startDate": "2022-02-10T00:00:00Z",
          "endDate": "2022-03-12T00:00:00Z",
          "termUnit": "P1M",
          "chargeDuration": null,
        },
      "autoRenew": true,
      "created": "2022-01-10T23:15:03.365988Z",
      "lastModified": "2022-02-14T20:26:04.5632549Z",
    },
    "purchaseToken": null
}
 

Пример полезных данных веб-перехватчика события продления:

// end user's subscription renewal
 
{
    "id": "<guid>",
    "activityId": "<guid>",
    "publisherId": "XXX",
    "offerId": "YYY",
    "planId": "plan1",
    "quantity": 100,
    "subscriptionId": "<guid>",
    "timeStamp": "2023-02-10T08:49:01.8613208Z",
    "action": "Renew",
    "status": "Succeeded",
    "operationRequestSource": "Azure",
    "subscription":
    {
      "id": "<guid>",
      "name": "Test",
      "publisherId": "XXX",
      "offerId": "YYY",
      "planId": "plan1",
      "quantity": 100,
      "beneficiary":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "purchaser":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "allowedCustomerOperations": ["Delete", "Update", "Read"],
      "sessionMode": "None",
      "isFreeTrial": false,
      "isTest": false,
      "sandboxType": "None",
      "saasSubscriptionStatus": "Subscribed",
      "term":
        {
          "startDate": "2022-02-10T00:00:00Z",
          "endDate": "2022-03-12T00:00:00Z",
          "termUnit": "P1M",
          "chargeDuration": null,
        },
      "autoRenew": true,
      "created": "2022-01-10T23:15:03.365988Z",
      "lastModified": "2022-02-14T20:26:04.5632549Z",
    },
  "purchaseToken": null,
}

Пример полезных данных веб-перехватчика события приостановки:


{
    "id": "<guid>",
    "activityId": "<guid>",
    "publisherId": "XXX",
    "offerId": "YYY",
    "planId": "plan1",
    "quantity": 100,
    "subscriptionId": "<guid>",
    "timeStamp": "2023-02-10T08:49:01.8613208Z",
    "action": "Suspend",
    "status": "Succeeded",
    "operationRequestSource": "Azure",
    "subscription":
    {
      "id": "<guid>",
      "name": "Test",
      "publisherId": "XXX",
      "offerId": "YYY",
      "planId": "plan1",
      "quantity": 100,
      "beneficiary":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "purchaser":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "allowedCustomerOperations": ["Delete", "Update", "Read"],
      "sessionMode": "None",
      "isFreeTrial": false,
      "isTest": false,
      "sandboxType": "None",
      "saasSubscriptionStatus": "Suspended",
      "term":
        {
          "startDate": "2022-02-10T00:00:00Z",
          "endDate": "2022-03-12T00:00:00Z",
          "termUnit": "P1M",
          "chargeDuration": null,
        },
      "autoRenew": true,
      "created": "2022-01-10T23:15:03.365988Z",
      "lastModified": "2022-02-14T20:26:04.5632549Z",
    },
  "purchaseToken": null,
}

Пример полезных данных веб-перехватчика события отмены подписки:

Это событие только для уведомления. Для этого события нет отправки в ACK.


{
    "id": "<guid>",
    "activityId": "<guid>",
    "publisherId": "XXX",
    "offerId": "YYY",
    "planId": "plan1",
    "quantity": 100,
    "subscriptionId": "<guid>",
    "timeStamp": "2023-02-10T08:49:01.8613208Z",
    "action": "Unsubscribe",
    "status": "Succeeded",
    "operationRequestSource": "Azure",
    "subscription":
    {
      "id": "<guid>",
      "name": "Test",
      "publisherId": "XXX",
      "offerId": "YYY",
      "planId": "plan1",
      "quantity": 100,
      "beneficiary":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "purchaser":
        {
          "emailId": XX@outlook.com,
          "objectId": "<guid>",
          "tenantId": "<guid>",
          "puid": "1234567890",
        },
      "allowedCustomerOperations": ["Delete", "Update", "Read"],
      "sessionMode": "None",
      "isFreeTrial": false,
      "isTest": false,
      "sandboxType": "None",
      "saasSubscriptionStatus": "Unsubscribed",
      "term":
        {
          "startDate": "2022-02-10T00:00:00Z",
          "endDate": "2022-03-12T00:00:00Z",
          "termUnit": "P1M",
          "chargeDuration": null,
        },
      "autoRenew": true,
      "created": "2022-01-10T23:15:03.365988Z",
      "lastModified": "2022-02-14T20:26:04.5632549Z",
    },
  "purchaseToken": null,
}

Защита веб-перехватчиков

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

  • Корпорация Майкрософт вызывает веб-перехватчики с заголовками авторизации, содержащими необходимые сведения для проверки вызовов. Чтобы веб-перехватчики могли получать заголовки авторизации, необходимо включить веб-перехватчики. (Не добавляйте сведения о авторизации или маркеры безопасности, такие как маркеры SAS непосредственно в URL-адресах веб-перехватчика. Такие веб-перехватчики могут не получить заголовки авторизации, которые корпорация Майкрософт отправляет при вызове веб-перехватчиков.

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

  • "aud": "Это идентификатор приложения удостоверений Майкрософт, который вы добавляете в техническую конфигурацию вашего предложения в Центре партнеров Майкрософт"

  • Appid или azp: это идентификатор ресурса, используемый при создании маркера авторизации издателя для вызова API выполнения SaaS. И в зависимости от настройки приложения вы можете увидеть это значение идентификатора ресурса в "appid" или "azp". Маркер имеет одно из двух утверждений, и вы должны реагировать соответствующим образом в коде.

  • "tid": "это идентификатор клиента Microsoft Entra, который вы добавляете в техническую конфигурацию вашего предложения в Центре партнеров Майкрософт"

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

Внимание

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

Разработка и тестирование

Чтобы приступить к процессу разработки, рекомендуется создать фиктивные отклики API на стороне издателя. Эти отклики могут быть созданы на основе примеров откликов, приведенных в этой статье.

Если издатель готов к сквозному тестированию:

  • Опубликуйте предложение SaaS для ограниченной аудитории предварительной версии и сохраните его предварительную версию.
  • Задайте для плана нулю, чтобы избежать активации фактических расходов на выставление счетов во время тестирования. Другим вариантом является установка ненулевой цены и отмена всех тестовых покупок в течение 24 часов.
  • Убедитесь, что вызываются все этапы процесса, чтобы сымитировать реальный сценарий с участием клиента.
  • Если партнер хочет протестировать полный процесс покупки и выставления счетов, для этого можно использовать предложение с ценой выше 0 долларов США. Счет за покупку выставляется, и будет создан счет.

Процесс покупки можно запустить на портале Azure или на сайтах Microsoft AppSource в зависимости от места публикации предложения.

Действия Изменить план, Изменить количество рабочих мест и Отменить подписку тестируются на стороне издателя. На стороне Майкрософт действие Отменить подписку может запускаться как на портале Azure, так и в Центре администрирования (портал, где осуществляется управление покупками в Microsoft AppSource). Действия "Изменить количество рабочих мест" и "Изменить план" можно выполнить только в Центре администрирования.

Поддержка

Возможности поддержки для издателя см. в разделе Поддержка коммерческой платформы в Центре партнеров.

Следующие шаги