Certaines sociétés, dont notre client, développent le produit via un réseau de partenaires. Par exemple, les grands magasins en ligne sont intégrés au service de livraison - vous commandez un produit et recevez bientôt un numéro de suivi pour le colis. Un autre exemple est lorsque vous achetez une assurance ou un billet Aeroexpress avec votre billet d'avion.
Pour cela, une API est utilisée, qui doit être délivrée aux partenaires via la passerelle API. Nous avons résolu ce problème. Dans cet article, nous vous donnerons les détails.
Donné : un écosystème et un portail API avec une interface où les utilisateurs s'enregistrent, reçoivent des informations, etc. Nous devons créer une passerelle API pratique et fiable. Dans le processus, nous devions fournir
- inscription,
- Contrôle de connexion API,
- surveiller la façon dont les utilisateurs utilisent le système final,
- comptabilisation des indicateurs d'activité.

Dans l'article, nous parlerons de notre expérience dans la création d'API Gateway, au cours de laquelle nous avons résolu les tâches suivantes :
- Authentification d'utilisateur,
- autorisation de l'utilisateur,
- modification de la demande initiale,
- demander la procuration,
- post-traitement de la réponse.
Il existe deux types de gestion d'API :
1. Standard, qui fonctionne comme suit. Avant de se connecter, l'utilisateur teste les fonctionnalités, puis paie et embarque sur son site. Le plus souvent, ils sont utilisés dans les petites et moyennes entreprises.
2. Large B2B API Management, lorsque l'entreprise prend pour la première fois la décision commerciale de se connecter, devient un partenaire de l'entreprise avec une obligation contractuelle, puis se connecte à l'API. Et une fois toutes les formalités réglées, l'entreprise reçoit l'accès aux tests, passe les tests et passe en production. Mais cela n'est pas possible sans une décision de la direction de se connecter.

Notre solution
Dans cette partie, nous parlerons de la création d'une API Gateway.
Les utilisateurs finaux de la passerelle API créée sont des partenaires de notre client. Nous avons déjà les contrats nécessaires pour chacun d'entre eux. Nous n'aurons qu'à étendre la fonctionnalité en marquant l'accès accordé à la passerelle. En conséquence, un processus de connexion et de gestion contrôlé est nécessaire.
Bien sûr, il était possible de prendre une solution toute faite pour résoudre le problème de la gestion des API et créer une API Gateway en particulier. Par exemple, cela pourrait être. Cela ne nous convenait pas, car dans notre cas, nous avions déjà un portail API et un énorme écosystème construit autour de celui-ci. Tous les utilisateurs ont déjà été enregistrés, ils ont déjà compris où et comment obtenir les informations nécessaires. Les interfaces nécessaires existaient déjà dans le portail API, nous n'avions besoin que de l'API Gateway. En fait, nous sommes engagés dans son développement.
Ce que nous appelons la passerelle API est une sorte de proxy. Ici, nous avions à nouveau le choix - vous pouvez écrire votre propre proxy ou choisir quelque chose de prêt à l'emploi. Dans ce cas, nous avons suivi la deuxième voie et choisi le bundle nginx + Lua. Pourquoi? Nous avions besoin d'un logiciel fiable et testé qui prend en charge la mise à l'échelle. Après l'implémentation, nous ne voulions pas vérifier à la fois l'exactitude de la logique métier et l'exactitude du proxy.
Chaque serveur Web dispose d'un pipeline de traitement des demandes. Dans le cas de nginx, cela ressemble à ceci :

(schéma de )
Notre objectif était de s'intégrer dans ce pipeline à un point où nous pouvons modifier la demande d'origine.
Nous voulons créer un proxy transparent afin que la demande reste fonctionnellement la même qu'elle est venue. Nous contrôlons uniquement l'accès à l'API finale, aidons la demande à y accéder. Si la demande était incorrecte, l'API finale devrait afficher l'erreur, mais pas nous. La seule raison pour laquelle nous pouvons refuser une demande est que le client n'y a pas accès.
Existe déjà pour nginx sur . Lua est un langage de script, il est très léger et facile à apprendre. Ainsi, nous avons implémenté la logique nécessaire en utilisant Lua.
La configuration nginx (une analogie avec la route de l'application), où tout le travail est fait, est tout à fait compréhensible. Il convient de noter ici la dernière directive - post_action.
location /middleware {
more_clear_input_headers Accept-Encoding;
lua_need_request_body on;
rewrite_by_lua_file 'middleware/rewrite.lua';
access_by_lua_file 'middleware/access.lua';
proxy_pass https://someurl.com;
body_filter_by_lua_file 'middleware/body_filter.lua';
post_action /process_session;
}
Considérez ce qui se passe dans cette configuration :
more_clear_input_headers — efface la valeur des en-têtes spécifiés après la directive.
lua_need_request_body - contrôle si le corps de la requête d'origine doit être lu avant d'exécuter les directives rewrite/access/access_by_lua ou non. Par défaut, nginx ne lit pas le corps d'une requête client, et si vous avez besoin d'y accéder, cette directive doit être définie sur on.
réécrire_par_lua_file - le chemin du script, qui décrit la logique de modification de la requête
access_by_lua_file — le chemin d'accès au script, qui décrit la logique qui vérifie l'accès à la ressource.
proxy_pass — url vers laquelle la requête sera proxy.
body_filter_by_lua_file — le chemin d'accès au script, qui décrit la logique de filtrage de la requête avant de la renvoyer au client.
Et, enfin, post_action - une directive officiellement non documentée avec laquelle vous pouvez effectuer d'autres actions après que la réponse a été donnée au client.
Ensuite, nous décrirons dans l'ordre comment nous avons résolu nos problèmes.
Autorisation/authentification et demande de modification
AUTORISATION
Nous avons construit l'autorisation et l'authentification à l'aide de l'accès par certificat. Il existe un certificat racine. Chaque nouveau client du client se voit générer son certificat personnel, avec lequel il peut accéder à l'API. Ce certificat est configuré dans la section serveur des paramètres nginx.
ssl on;
ssl_certificate /usr/local/openresty/nginx/ssl/cert.pem;
ssl_certificate_key /usr/local/openresty/nginx/ssl/cert.pem;
ssl_client_certificate /usr/local/openresty/nginx/ssl/ca.crt;
ssl_verify_client on;modification
Une juste question peut se poser : que faire d'un client certifié si on veut soudainement le déconnecter du système ? Ne réémettez pas de certificats pour tous les autres clients.
Nous avons donc abordé en douceur la tâche suivante - modifier la demande d'origine. La demande initiale du client, en règle générale, n'est pas valable pour le système final. L'une des tâches consiste à ajouter les parties manquantes à la demande pour la rendre valide. Le fait est que les données manquantes sont différentes pour chaque client. Nous savons qu'un client vient nous voir avec un certificat à partir duquel nous pouvons prendre une empreinte digitale et extraire les données client nécessaires de la base de données.
Si à un moment donné vous avez besoin de déconnecter le client de notre service, ses données disparaîtront de la base de données et il ne pourra rien faire.
Travailler avec les données clients
Nous devions rendre la solution hautement disponible, en particulier la manière dont nous obtenons les données clients. La difficulté est que la source première de ces données est un service tiers qui ne garantit pas un débit ininterrompu et suffisamment élevé.
Par conséquent, nous devions assurer une haute disponibilité des données clients. Comme outil, nous avons choisi qui nous offre :
- accès rapide aux données
- la possibilité d'organiser un cluster de plusieurs nœuds avec des données répliquées sur différents nœuds.
Nous avons opté pour la stratégie la plus simple pour fournir des données au cache :

Le travail avec le système final s'effectue au cours des sessions et le nombre maximum est limité. Si le client n'a pas fermé la session, nous devrons le faire.
Les données de session ouvertes proviennent du système final et sont initialement traitées du côté Lua. Nous avons décidé d'utiliser Hazelcast pour stocker ces données avec un travail .NET. Ensuite, à certains intervalles, nous vérifions le droit à la vie des sessions ouvertes et fermons celles qui sont pourries.
Accéder à Hazelcast depuis Lua et .NET
Il n'y a pas de clients Lua pour travailler avec Hazelcast, mais Hazelcast a une API REST, que nous avons décidé d'utiliser. Pour .NET il y a , par lequel nous avions prévu d'accéder aux données Hazelcast côté .NET. Mais ce n'était pas là.

Lors du stockage de données via REST et de la récupération de données via un client .NET, différents sérialiseurs et désérialiseurs sont utilisés. Par conséquent, il est impossible de mettre des données via REST, mais de les obtenir via le client .NET et vice versa.
S'il y a des intéressés, nous vous en dirons plus sur ce problème dans un article séparé. Spoiler - sur le schéma.

Journalisation et surveillance
Notre standard d'entreprise pour la journalisation via .NET est Serilog, tous les journaux finissent dans Elasticsearch, et nous les analysons via Kibana. Je voudrais faire quelque chose de similaire dans ce cas. Le seul travailler avec Elastic sur Lua, qui a été trouvé, s'est cassé dès le premier besoin. Et nous avons utilisé Fluentd.
- solution open source pour fournir une couche unique de journalisation des applications. Vous permet de collecter des journaux à partir de différentes couches de l'application, puis de les diffuser dans une seule source.
API Gateway fonctionne dans K8S, nous avons donc décidé d'ajouter un conteneur avec fluentd dans le même module afin d'écrire des journaux sur le port tcp ouvert existant fluentd.
Nous avons également exploré comment fluentd se comporterait s'il n'avait aucune connexion à Elasticsearch. Pendant deux jours, des requêtes ont été envoyées en continu à la passerelle, des journaux ont été envoyés à fluentd, mais fluentd a été banni d'IP Elastic. Une fois la connexion rétablie, fluentd a parfaitement dépassé tous les journaux dans Elastic.
Conclusion
L'approche de mise en œuvre choisie nous a permis de livrer un produit vraiment fonctionnel à l'environnement de combat en seulement 2.5 mois.
S'il vous arrive un jour de faire de telles choses, nous vous conseillons d'abord de bien comprendre quel problème vous résolvez et quelles ressources vous avez déjà. Soyez conscient de la complexité de l'intégration avec les systèmes de gestion d'API existants.
Comprenez par vous-même ce que vous allez développer exactement - uniquement la logique métier pour le traitement des demandes ou, comme cela pourrait être dans notre cas, l'ensemble du proxy. N'oubliez pas que tout ce que vous faites vous-même doit être soigneusement testé par la suite.
Source: habr.com
