Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
DOTYCZY: Wszystkie warstwy usługi API Management
Zasady dostępne w usłudze Azure API Management mogą wykonywać szeroką gamę przydatnych prac w oparciu o przychodzące żądanie, odpowiedź wychodzącą i podstawowe informacje o konfiguracji. Jednak możliwość interakcji z usługami zewnętrznymi z poziomu zasad usługi API Management otwiera o wiele więcej możliwości.
W poprzednich artykułach pokazano, jak korzystać z usługi Azure Event Hubs na potrzeby rejestrowania, monitorowania i analizy. W tym artykule przedstawiono zasady, które umożliwiają interakcję z dowolną zewnętrzną usługą opartą na protokole HTTP. Te zasady mogą służyć do wyzwalania zdarzeń zdalnych lub pobierania informacji używanych do manipulowania oryginalnym żądaniem i odpowiedzią w jakiś sposób.
Wyślij jednokierunkowe żądanie
Prawdopodobnie najprostszą interakcją zewnętrzną jest styl żądania fire-and-forget, który pozwala na powiadomienie usługi zewnętrznej o jakimś ważnym zdarzeniu. Zasady choose przepływu sterowania mogą służyć do wykrywania dowolnego rodzaju warunku, który cię interesuje. Jeśli warunek jest spełniony, możesz wysłać zewnętrzne żądanie HTTP, używając polisy send-one-way-request. To żądanie może dotyczyć systemu obsługi komunikatów, takiego jak Hipchat lub Slack, albo interfejsu API poczty, takiego jak SendGrid lub MailChimp, albo w przypadku krytycznych zdarzeń pomocy technicznej, takich jak PagerDuty. Wszystkie te systemy obsługi komunikatów mają proste interfejsy API HTTP, które można wywołać.
Alerty z usługą Slack
W poniższym przykładzie pokazano, jak wysłać wiadomość do pokoju rozmów usługi Slack, jeśli kod stanu odpowiedzi HTTP jest większy lub równy 500. Błąd zakresu 500 wskazuje na problem z API zaplecza, którego klient API nie może rozwiązać samodzielnie. Zwykle wymaga pewnego rodzaju interwencji ze strony usługi API Management.
<choose>
<when condition="@(context.Response.StatusCode >= 500)">
<send-one-way-request mode="new">
<set-url>https://hooks.slack.com/services/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</set-url>
<set-method>POST</set-method>
<set-body>@{
return new JObject(
new JProperty("username","APIM Alert"),
new JProperty("icon_emoji", ":ghost:"),
new JProperty("text", String.Format("{0} {1}\nHost: {2}\n{3} {4}\n User: {5}",
context.Request.Method,
context.Request.Url.Path + context.Request.Url.QueryString,
context.Request.Url.Host,
context.Response.StatusCode,
context.Response.StatusReason,
context.User.Email
))
).ToString();
}</set-body>
</send-one-way-request>
</when>
</choose>
Slack ma pojęcie przychodzących webhooków. Po skonfigurowaniu przychodzącego elementu webhook usługa Slack generuje specjalny adres URL, który umożliwia wykonywanie podstawowego żądania POST i przekazywanie komunikatu do kanału usługi Slack. Treść utworzonego kodu JSON jest oparta na formacie zdefiniowanym przez usługę Slack.
Czy podejście „ustaw i zapomnij” jest wystarczająco dobre?
Istnieją pewne kompromisy przy korzystaniu z podejścia "odpal i zapomnij" w żądaniach. Jeśli z jakiegoś powodu żądanie zakończy się niepowodzeniem, błąd nie zostanie zgłoszony. W takiej sytuacji złożoność pomocniczego systemu raportowania błędów i dodatkowy koszt wydajności oczekiwania na odpowiedź nie jest uzasadniony. W przypadku scenariuszy, w których niezbędne jest sprawdzenie odpowiedzi, zasady wysyłania żądań są lepszym rozwiązaniem.
Wyślij żądanie
Zasady send-request umożliwiają korzystanie z usługi zewnętrznej do wykonywania złożonych funkcji przetwarzania i zwracania danych do usługi API Management, która może służyć do dalszego przetwarzania zasad.
Autoryzowanie tokenów referencyjnych
Główną funkcją usługi API Management jest ochrona zasobów zaplecza. Jeśli serwer autoryzacji używany przez interfejs API tworzy tokeny sieci Web JSON (JWTs) w ramach przepływu OAuth2, podobnie jak robi to Microsoft Entra ID, to możesz użyć polityki validate-jwt lub validate-azure-ad-token, aby zweryfikować ważność tokenu. Niektóre serwery autoryzacji tworzą tokeny referencyjne , których nie można zweryfikować bez wykonywania wywołania zwrotnego na serwerze autoryzacji.
Standaryzacja introspekcji
W przeszłości nie było ustandaryzowanego sposobu weryfikowania tokenu referencyjnego z serwerem autoryzacji. Jednak internet engineering Task Force (IETF) niedawno opublikował proponowany standard RFC 7662 , który definiuje sposób, w jaki serwer zasobów może zweryfikować ważność tokenu.
Wyodrębnianie tokenu
Pierwszym krokiem jest wyodrębnienie tokenu z nagłówka Autoryzacji. Wartość nagłówka powinna być sformatowana przy użyciu schematu Bearer autoryzacji, pojedynczego miejsca, a następnie tokenu autoryzacji zgodnie z RFC 6750. Niestety istnieją przypadki, w których schemat autoryzacji zostanie pominięty. Aby uwzględnić to pominięcie podczas analizowania, usługa API Management dzieli wartość nagłówka na spację i wybiera ostatni ciąg z zwracanej tablicy ciągów. Ta metoda zapewnia obejście dla źle sformatowanych nagłówków autoryzacji.
<set-variable name="token" value="@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param").Split(' ').Last())" />
Wykonywanie żądania weryfikacji
Gdy usługa API Management ma token autoryzacji, usługa API Management może wysłać żądanie weryfikacji tokenu. RFC 7662 nazywa ten proces introspekcją i wymaga przesłania formularza HTML do zasobu introspekcji. Formularz HTML musi zawierać co najmniej parę klucz/wartość z kluczem token. To żądanie do serwera autoryzacji musi być również uwierzytelnione, aby upewnić się, że złośliwi klienci nie mogą przeszukiwać prawidłowych tokenów.
<send-request mode="new" response-variable-name="tokenstate" timeout="20" ignore-error="true">
<set-url>https://microsoft-apiappec990ad4c76641c6aea22f566efc5a4e.azurewebsites.net/introspection</set-url>
<set-method>POST</set-method>
<set-header name="Authorization" exists-action="override">
<value>basic dXNlcm5hbWU6cGFzc3dvcmQ=</value>
</set-header>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>@($"token={(string)context.Variables["token"]}")</set-body>
</send-request>
Sprawdzanie odpowiedzi
Atrybut response-variable-name jest używany do udzielenia dostępu do zwróconej odpowiedzi. Nazwa zdefiniowana w tej właściwości może służyć jako klucz do słownika context.Variables, aby uzyskać dostęp do obiektu IResponse.
Z obiektu odpowiedzi można pobrać treść i RFC 7622 informuje usługę API Management, że odpowiedź musi być obiektem JSON i musi zawierać co najmniej właściwość o nazwie active , która jest wartością logiczną. Jeśli active wartość ma wartość true, token jest uznawany za prawidłowy.
Alternatywnie, jeśli serwer autoryzacji nie zawiera "active" pola, aby wskazać, czy token jest prawidłowy, użyj narzędzia klienta HTTP, takiego jak curl , aby określić, jakie właściwości są ustawione w prawidłowym tokenie. Jeśli na przykład prawidłowa odpowiedź tokenu zawiera właściwość o nazwie "expires_in", sprawdź, czy ta nazwa właściwości istnieje w odpowiedzi serwera autoryzacji w następujący sposób:
<when condition="@(((IResponse)context.Variables["tokenstate"]).Body.As<JObject>().Property("expires_in") == null)">
Raportowanie błędu
Możesz użyć <choose> zasady, aby wykryć, czy token jest nieprawidłowy, a jeśli tak, zwrócić odpowiedź 401.
<choose>
<when condition="@((bool)((IResponse)context.Variables["tokenstate"]).Body.As<JObject>()["active"] == false)">
<return-response response-variable-name="existing response variable">
<set-status code="401" reason="Unauthorized" />
<set-header name="WWW-Authenticate" exists-action="override">
<value>Bearer error="invalid_token"</value>
</set-header>
</return-response>
</when>
</choose>
Zgodnie z RFC 6750, który opisuje sposób bearer użycia tokenów, usługa API Management zwraca również nagłówek z odpowiedzią WWW-Authenticate 401. Usługa WWW-Authenticate ma na celu poinstruowanie klienta o sposobie konstruowania prawidłowo autoryzowanego żądania. Ze względu na szeroką gamę metod możliwych w strukturze OAuth2 trudno jest przekazać wszystkie potrzebne informacje. Na szczęście trwają prace, aby pomóc klientom odkryć, jak prawidłowo autoryzować żądania do serwera zasobów.
Ostateczne rozwiązanie
Na końcu uzyskasz następujące zasady:
<inbound>
<!-- Extract Token from Authorization header parameter -->
<set-variable name="token" value="@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param").Split(' ').Last())" />
<!-- Send request to Token Server to validate token (see RFC 7662) -->
<send-request mode="new" response-variable-name="tokenstate" timeout="20" ignore-error="true">
<set-url>https://microsoft-apiappec990ad4c76641c6aea22f566efc5a4e.azurewebsites.net/introspection</set-url>
<set-method>POST</set-method>
<set-header name="Authorization" exists-action="override">
<value>basic dXNlcm5hbWU6cGFzc3dvcmQ=</value>
</set-header>
<set-header name="Content-Type" exists-action="override">
<value>application/x-www-form-urlencoded</value>
</set-header>
<set-body>@($"token={(string)context.Variables["token"]}")</set-body>
</send-request>
<choose>
<!-- Check active property in response -->
<when condition="@((bool)((IResponse)context.Variables["tokenstate"]).Body.As<JObject>()["active"] == false)">
<!-- Return 401 Unauthorized with http-problem payload -->
<return-response response-variable-name="existing response variable">
<set-status code="401" reason="Unauthorized" />
<set-header name="WWW-Authenticate" exists-action="override">
<value>Bearer error="invalid_token"</value>
</set-header>
</return-response>
</when>
</choose>
<base />
</inbound>
Ten przykład jest tylko jednym z wielu, które pokazują, jak politykę send-request można użyć do zintegrowania przydatnych usług zewnętrznych z procesem żądań i odpowiedzi przepływających przez usługę API Management.
Kompozycja odpowiedzi
Zasady send-request mogą służyć do ulepszania podstawowego żądania do systemu zaplecza, jak pokazano w poprzednim przykładzie, lub mogą służyć do całkowitego zastąpienia wywołania do systemu zaplecza. Przy użyciu tej techniki można łatwo tworzyć zasoby złożone, które są agregowane z wielu różnych systemów.
Tworzenie pulpitu nawigacyjnego
Czasami chcesz mieć możliwość uwidocznienia informacji, które istnieją w wielu systemach zaplecza, na przykład w celu obsługi pulpitu nawigacyjnego. Kluczowe wskaźniki wydajności (KPI) pochodzą ze wszystkich różnych zapleczy, ale nie chcesz zapewniać bezpośredniego dostępu do nich. Mimo to byłoby miło, gdyby wszystkie informacje mogły zostać pobrane w jednym żądaniu. Być może najpierw niektóre informacje w zapleczu wymagają przetwarzania i trochę oczyszczenia! Możliwość buforowania tego złożonego zasobu byłaby przydatnym sposobem zmniejszenia obciążenia zaplecza, dlatego że użytkownicy mają zwyczaj naciskać klawisz F5, aby zobaczyć, czy ich niewydajne metryki mogą się zmienić.
Fałszowanie zasobu
Pierwszym krokiem do utworzenia zasobu pulpitu nawigacyjnego jest skonfigurowanie nowej operacji w witrynie Azure Portal. Ta funkcja zastępcza jest używana do konfigurowania polityki kompozycji w celu budowy zasobu dynamicznego.
Wykonywanie żądań
Po utworzeniu operacji można skonfigurować zasady specjalnie dla tej operacji.
Pierwszym krokiem jest wyodrębnienie wszystkich parametrów zapytania z żądania przychodzącego, aby można było przekazać je do zaplecza. W tym przykładzie pulpit nawigacyjny wyświetla informacje na podstawie okresu czasu i dlatego ma parametr fromDate oraz parametr toDate. Możesz użyć set-variable zasady, aby wyodrębnić informacje z adresu URL żądania.
<set-variable name="fromDate" value="@(context.Request.Url.Query["fromDate"].Last())">
<set-variable name="toDate" value="@(context.Request.Url.Query["toDate"].Last())">
Po uzyskaniu tych informacji możesz wysyłać żądania do wszystkich systemów zaplecza. Każde żądanie tworzy nowy adres URL z informacjami o parametrach i wywołuje odpowiedni serwer i przechowuje odpowiedź w zmiennej kontekstowej.
<send-request mode="new" response-variable-name="revenuedata" timeout="20" ignore-error="true">
<set-url>@($"https://accounting.acme.com/salesdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
<set-method>GET</set-method>
</send-request>
<send-request mode="new" response-variable-name="materialdata" timeout="20" ignore-error="true">
<set-url>@($"https://inventory.acme.com/materiallevels?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
<set-method>GET</set-method>
</send-request>
<send-request mode="new" response-variable-name="throughputdata" timeout="20" ignore-error="true">
<set-url>@($"https://production.acme.com/throughput?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
<set-method>GET</set-method>
</send-request>
<send-request mode="new" response-variable-name="accidentdata" timeout="20" ignore-error="true">
<set-url>@($"https://production.acme.com/accidentdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")</set-url>
<set-method>GET</set-method>
</send-request>
Usługa API Management wysyła te żądania sekwencyjnie.
Odpowiadanie
Aby utworzyć złożoną odpowiedź, możesz użyć return-response policy. Element set-body może użyć wyrażenia, aby skonstruować nowy JObject element ze wszystkimi reprezentacjami składników osadzonymi jako właściwości.
<return-response response-variable-name="existing response variable">
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>
@(new JObject(new JProperty("revenuedata",((IResponse)context.Variables["revenuedata"]).Body.As<JObject>()),
new JProperty("materialdata",((IResponse)context.Variables["materialdata"]).Body.As<JObject>()),
new JProperty("throughputdata",((IResponse)context.Variables["throughputdata"]).Body.As<JObject>()),
new JProperty("accidentdata",((IResponse)context.Variables["accidentdata"]).Body.As<JObject>())
).ToString())
</set-body>
</return-response>
Pełne zasady wyglądają następująco:
<policies>
<inbound>
<set-variable name="fromDate" value="@(context.Request.Url.Query["fromDate"].Last())">
<set-variable name="toDate" value="@(context.Request.Url.Query["toDate"].Last())">
<send-request mode="new" response-variable-name="revenuedata" timeout="20" ignore-error="true">
<set-url>@($"https://accounting.acme.com/salesdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
<set-method>GET</set-method>
</send-request>
<send-request mode="new" response-variable-name="materialdata" timeout="20" ignore-error="true">
<set-url>@($"https://inventory.acme.com/materiallevels?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
<set-method>GET</set-method>
</send-request>
<send-request mode="new" response-variable-name="throughputdata" timeout="20" ignore-error="true">
<set-url>@($"https://production.acme.com/throughput?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
<set-method>GET</set-method>
</send-request>
<send-request mode="new" response-variable-name="accidentdata" timeout="20" ignore-error="true">
<set-url>@($"https://production.acme.com/accidentdata?from={(string)context.Variables["fromDate"]}&to={(string)context.Variables["fromDate"]}")"</set-url>
<set-method>GET</set-method>
</send-request>
<return-response response-variable-name="existing response variable">
<set-status code="200" reason="OK" />
<set-header name="Content-Type" exists-action="override">
<value>application/json</value>
</set-header>
<set-body>
@(new JObject(new JProperty("revenuedata",((IResponse)context.Variables["revenuedata"]).Body.As<JObject>()),
new JProperty("materialdata",((IResponse)context.Variables["materialdata"]).Body.As<JObject>()),
new JProperty("throughputdata",((IResponse)context.Variables["throughputdata"]).Body.As<JObject>()),
new JProperty("accidentdata",((IResponse)context.Variables["accidentdata"]).Body.As<JObject>())
).ToString())
</set-body>
</return-response>
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
</policies>
Podsumowanie
Usługa Azure API Management udostępnia elastyczne zasady, które można selektywnie stosować do ruchu HTTP i umożliwiają tworzenie usług zaplecza. Niezależnie od tego, czy chcesz ulepszyć bramę interfejsu API za pomocą funkcji powiadomień, weryfikacji, walidacji, czy tworzyć nowe zasoby złożone na podstawie wielu usług backendowych, send-request i powiązane polityki otwierają świat możliwości.