Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
S’APPLIQUE À : Tous les niveaux de Gestion des API
Les stratégies disponibles dans le service Gestion des API Azure permettent d’exécuter un large éventail de tâches utiles reposant strictement sur la requête entrante, la réponse sortante et les informations de configuration de base. En revanche, la possibilité d’interagir avec des services externes à partir des stratégies de gestion des API ouvre bien davantage d’opportunités.
Dans les articles précédents, vous avez vu comment interagir avec le service Azure Event Hubs pour la journalisation, la supervision et l’analytique. Cet article décrit les stratégies qui vous permettent d’interagir avec n’importe quel service HTTP externe. Vous pouvez utiliser ces stratégies pour déclencher des événements à distance ou pour récupérer des informations servant à manipuler la requête d’origine et la réponse d’une certaine façon.
Send-One-Way-Request (Envoyer une requête à sens unique)
L’interaction externe la plus simple est peut-être le style de requête fire-and-forget qui permet à un service externe d’être averti d’un type d’événement important. La stratégie choose de flux de contrôle peut être utilisée pour détecter tout type de condition qui vous intéresse. Si la condition est remplie, vous pouvez exécuter une requête HTTP externe en utilisant la stratégie send-one-way-request. Cette demande peut être adressée à un système de messagerie tel que Hipchat ou Slack, ou à une API de messagerie comme SendGrid ou MailChimp, ou pour des incidents de support critiques comme PagerDuty. Tous ces systèmes de messagerie comportent des API HTTP simples qui peuvent être facilement appelées.
Alerte avec Slack
L’exemple suivant montre comment envoyer un message à une salle de conversation Slack si le code d’état de la réponse HTTP est supérieur ou égal à 500. Une erreur de plage 500 indique un problème avec l’API back-end que le client de l’API ne peut pas résoudre lui-même. Il nécessite généralement une intervention de quelque sorte sur la partie Gestion des API.
<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 inclut la notion de Webhook entrant. Lorsqu’il configure un hook web entrant, Slack génère une URL spéciale, ce qui vous permet d’effectuer une requête POST de base et de transmettre un message dans le canal Slack. Le corps JSON que vous créez repose sur un format défini par Slack.
Le style « fire and forget » est-il suffisant ?
L’utilisation d’un style « fire and forget » de requête implique certains compromis. Si, pour une raison quelconque, la demande échoue, l’échec n’est pas signalé. Dans ce cas, la complexité d’un système de création de rapports d’échec secondaire et le coût de performances supplémentaire d’attente de la réponse n’est pas justifié. Pour les scénarios où il est essentiel de vérifier la réponse, la stratégie de demande d’envoi est une meilleure option.
send-request
La stratégie send-request permet d’utiliser un service externe pour exécuter des fonctions de traitement complexes et retourner des données au service Gestion des API qui peuvent être utilisées pour d’autres traitements de stratégie.
Autorisation des jetons de référence
Une fonction majeure de la gestion des API consiste à protéger les ressources principales. Si le serveur d’autorisation utilisé par votre API crée JSON Web Tokens (JWTs) dans le cadre de son flux OAuth2, comme Microsoft Entra ID le fait, alors vous pouvez utiliser la politique validate-jwt ou la politique validate-azure-ad-token pour vérifier la validité du jeton. Certains serveurs d’autorisation créent les jetons de référence qui ne peuvent pas être vérifiés sans effectuer de rappel au serveur d’autorisation.
Introspection normalisée
Dans le passé, il n’y avait aucun moyen standardisé de vérifier un jeton de référence avec un serveur d’autorisation. Toutefois, l’Internet Engineering Task Force (IETF) a récemment publié la norme RFC 7662 proposée qui définit la façon dont un serveur de ressources peut vérifier la validité d’un jeton.
Extraction du jeton
La première étape consiste à extraire le jeton de l’en-tête d’autorisation. Conformément à la norme Bearer, la valeur d’en-tête doit prendre la forme du modèle d’autorisation , suivi d’un seul espace et du jeton d’autorisation. Malheureusement, il existe des cas où le modèle d’autorisation est omis. Pour tenir compte de cette omission lors de l’analyse, Gestion des API fractionne la valeur d’en-tête sur un espace et sélectionne la dernière chaîne dans le tableau de chaînes retourné. Cette méthode fournit une solution de contournement pour les en-têtes d’autorisation mal mis en forme.
<set-variable name="token" value="@(context.Request.Headers.GetValueOrDefault("Authorization","scheme param").Split(' ').Last())" />
Requête de validation
Une fois que le service Gestion des API dispose du jeton d’autorisation, il peut exécuter la requête de validation du jeton. La norme RFC 7662 appelle ce processus « introspection » et vous oblige à adresser une requête POST de formulaire HTML à la ressource d’introspection. Le formulaire HTML doit contenir au moins une paire clé/valeur avec la clé token. Cette demande adressée au serveur d’autorisation doit également être authentifiée pour s’assurer que les clients malveillants ne peuvent pas effectuer de trawling pour les jetons valides.
<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>
Vérification de la réponse
L’attribut response-variable-name est utilisé pour donner accès à la réponse retournée. Le nom défini dans cette propriété peut être utilisé comme clé dans le dictionnaire context.Variables pour accéder à l’objet IResponse.
Vous pouvez récupérer le corps à partir de l’objet de réponse, et la norme RFC 7622 indique au service Gestion des API que la réponse doit être un objet JSON et contenir au moins une propriété appelée active correspondant à une valeur booléenne. Lorsque active est vrai, le jeton est considéré comme valide.
Sinon, si le serveur d’autorisation n’inclut pas le "active" champ pour indiquer si le jeton est valide, utilisez un outil client HTTP tel que curl pour déterminer les propriétés définies dans un jeton valide. Par exemple, si une réponse de jeton valide contient une propriété appelée "expires_in", vérifiez si ce nom de propriété existe dans la réponse du serveur d’autorisation de cette façon :
<when condition="@(((IResponse)context.Variables["tokenstate"]).Body.As<JObject>().Property("expires_in") == null)">
Signalement d’un échec
Vous pouvez utiliser une stratégie <choose> pour détecter si le jeton n’est pas valide et, le cas échéant, renvoyer une réponse 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>
Selon RFC 6750, qui décrit la manière dont les jetons bearer doivent être utilisés, la gestion des API retourne également un en-tête WWW-Authenticate avec la réponse 401. L’élément WWW-Authenticate a pour but d’informer un client sur la manière de créer une requête dûment autorisée. En raison de la grande variété d’approches possibles avec l’infrastructure OAuth2, il est difficile de communiquer toutes les informations nécessaires. Heureusement, tous les efforts sont déployés pour aider les clients à découvrir comment autoriser correctement les requêtes adressées à un serveur de ressources.
Solution finale
À la fin, vous obtenez la stratégie suivante :
<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>
Cet exemple n’est qu’un des nombreux qui montrent comment la send-request stratégie peut être utilisée pour intégrer des services externes utiles dans le processus de requêtes et de réponses qui transitent par le service Gestion des API.
Rédaction de réponse
La send-request stratégie peut être utilisée pour améliorer une requête principale vers un système back-end, comme vous l’avez vu dans l’exemple précédent, ou elle peut être utilisée pour remplacer complètement l’appel principal. Cette technique vous permet de créer facilement des ressources composites qui sont agrégées à partir de plusieurs systèmes distincts.
Génération d’un tableau de bord
Vous avez parfois besoin d’exposer des informations qui existent dans plusieurs systèmes principaux, par exemple, pour piloter un tableau de bord. Les indicateurs de performance clés (KPI) proviennent de tous les différents back-ends, mais vous préférez ne pas leur fournir un accès direct. Néanmoins, il serait agréable si toutes les informations pourraient être récupérées dans une seule demande. Certaines informations principales ont peut-être besoin d’être coupées en rondelles ou en tranches, voire d’être assainies dans un premier temps. La possibilité de mettre en cache cette ressource composite serait un moyen utile de réduire la charge du serveur, car vous savez que les utilisateurs ont l’habitude de marteler la touche F5 afin de voir si leurs indicateurs de performance sous-optimaux peuvent changer.
Simulation de la ressource
La première étape pour générer la ressource de tableau de bord consiste à configurer une nouvelle opération dans le portail Azure. Cette opération de substitution est utilisée pour configurer une politique de composition afin de construire la ressource dynamique.
Construction des requêtes
Une fois l’opération créée, vous pouvez configurer une stratégie spécifiquement pour cette opération.
La première étape consiste à extraire les paramètres de requête à partir de la requête entrante, de façon à pouvoir les transférer vers le serveur principal. Dans cet exemple, le tableau de bord affiche des informations reposant sur une période donnée et comporte donc des paramètres fromDate et toDate. Vous pouvez utiliser la stratégie set-variable pour extraire les informations de l’URL de la requête.
<set-variable name="fromDate" value="@(context.Request.Url.Query["fromDate"].Last())">
<set-variable name="toDate" value="@(context.Request.Url.Query["toDate"].Last())">
Une fois que vous disposez de ces informations, vous pouvez adresser des requêtes à tous les systèmes principaux. Chaque requête construit une nouvelle URL avec les informations de paramètre, puis appelle son serveur respectif et enregistre la réponse dans une variable de contexte.
<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>
Gestion des API envoie ces requêtes de manière séquentielle.
Réponse
Pour construire la réponse composite, vous pouvez utiliser la stratégie return-response. L’élément set-body peut utiliser une expression pour construire un nouveau JObject avec toutes les représentations de composant incorporées en tant que propriétés.
<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>
La stratégie complète se présente comme suit :
<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>
Résumé
Le service de gestion des API Azure offre des stratégies flexibles que vous pouvez appliquer de façon sélective au trafic HTTP et permet de composer des services principaux. Que vous vouliez améliorer votre passerelle API avec des fonctions d’alerte, des fonctionnalités de vérification et de validation ou créer des ressources composites reposant sur plusieurs services principaux, la stratégie send-request et les stratégies associées vous ouvrent un monde de possibilités.