Управление API Azure. Использование OAuth для защиты соединения между шлюзом и серверной частью? - PullRequest
0 голосов
/ 14 декабря 2018

У нас есть существующий бэкэнд, который защищен стандартным потоком учетных данных OAuth.Мы перемещаем весь трафик для прохождения через шлюз API Azure и нашли следующую политику для использования OAuth (источник: Используйте OAuth2 для авторизации между шлюзом и бэкэндом ).

<!-- The policy defined in this file provides an example of using OAuth2 for authorization between the gateway and a backend. -->
<!-- It shows how to obtain an access token from AAD and forward it to the backend. -->

<!-- Send request to AAD to obtain a bearer token -->
<!-- Parameters: authorizationServer - format https://login.windows.net/TENANT-GUID/oauth2/token -->
<!-- Parameters: scope - a URI encoded scope value -->
<!-- Parameters: clientId - an id obtained during app registration -->
<!-- Parameters: clientSecret - a URL encoded secret, obtained during app registration -->

<!-- Copy the following snippet into the inbound section. -->

<policies>
  <inbound>
    <base />
      <send-request ignore-error="true" timeout="20" response-variable-name="bearerToken" mode="new">
        <set-url>{{authorizationServer}}</set-url>
        <set-method>POST</set-method>
        <set-header name="Content-Type" exists-action="override">
          <value>application/x-www-form-urlencoded</value>
        </set-header>
        <set-body>
          @{
          return "client_id={{clientId}}&resource={{scope}}&client_secret={{clientSecret}}&grant_type=client_credentials";
          }
        </set-body>
      </send-request>

      <set-header name="Authorization" exists-action="override">
        <value>
          @("Bearer " + (String)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>()["access_token"])
      </value>
      </set-header>

      <!--  Don't expose APIM subscription key to the backend. -->
      <set-header exists-action="delete" name="Ocp-Apim-Subscription-Key"/>
  </inbound>
  <backend>
    <base />
  </backend>
  <outbound>
    <base />
  </outbound>
  <on-error>
    <base />
  </on-error>
</policies>

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

Есть ли способ повторно использовать токен (если он все еще действителен) при выполнении вызововмежду шлюзом и бэкэндом?

1 Ответ

0 голосов
/ 17 декабря 2018

Попробуйте использовать cache-store-value и cache-get-value для хранения токена в кеше.Если вы предварительно проверяете токен, вы можете поместить int в кеш с временем его истечения как ttl.Просто убедитесь, что у вас есть запасная логика на случай, если кэшированный токен не работает.

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

<policies>
    <inbound>
        <base />
        <cache-lookup-value key="bearerToken" variable-name="bearerToken" />
        <choose>
            <when condition="@(!context.Variables.ContainsKey("bearerToken"))">
                <send-request ignore-error="true" timeout="20" response-variable-name="bearerToken" mode="new">
                    <set-url>{{authorizationServer}}</set-url>
                    <set-method>POST</set-method>
                    <set-header name="Content-Type" exists-action="override">
                        <value>application/x-www-form-urlencoded</value>
                    </set-header>
                    <set-body>@("client_id={{clientId}}&resource={{scope}}&client_secret={{clientSecret}}&grant_type=client_credentials")</set-body>
                </send-request>
                <set-variable name="bearerToken" value="@((string)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>()["access_token"])" />
                <cache-store-value key="bearerToken" value="@((string)context.Variables["bearerToken"])" duration="60" />
                <set-variable name="cachedToken" value="@(false)" />
            </when>
            <otherwise>
                <set-variable name="cachedToken" value="@(true)" />
            </otherwise>
        </choose>

        <!--  Don't expose APIM subscription key to the backend. -->
        <set-header exists-action="delete" name="Ocp-Apim-Subscription-Key"/>
    </inbound>
    <backend>
        <retry condition="@((bool)context.Variables["cachedToken"] && context.Response.StatusCode == 401)" count="1" interval="0" first-fast-retry="true">
            <choose>
                <when condition="@(context.Response.StatusCode == 401)">
                    <send-request ignore-error="true" timeout="20" response-variable-name="bearerToken" mode="new">
                        <set-url>{{authorizationServer}}</set-url>
                        <set-method>POST</set-method>
                        <set-header name="Content-Type" exists-action="override">
                            <value>application/x-www-form-urlencoded</value>
                        </set-header>
                        <set-body>@("client_id={{clientId}}&resource={{scope}}&client_secret={{clientSecret}}&grant_type=client_credentials")</set-body>
                    </send-request>
                    <set-variable name="bearerToken" value="@((string)((IResponse)context.Variables["bearerToken"]).Body.As<JObject>()["access_token"])" />
                    <cache-store-value key="bearerToken" value="@((string)context.Variables["bearerToken"])" duration="60" />
                    <set-variable name="cachedToken" value="@(false)" />
                </when>
            </choose>

            <set-header name="Authorization" exists-action="override">
                <value>@("Bearer " + (string)context.Variables["bearerToken"])</value>
            </set-header>

            <forward-request />
        </retry>
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>
...