Noen selskaper, inkludert vĂ„r kunde, utvikler produkter gjennom et partnernettverk. For eksempel er store nettbutikker integrert med leveringsservice â du bestiller et produkt og fĂ„r snart et sporingsnummer for pakken. Et annet eksempel er at du kjĂžper en forsikring eller billett til ekspresstoget sammen med flybilletten.
Dette gjÞres ved hjelp av et API som mÄ gis til partnerne via API Gateway. Denne oppgaven har vi lÞst. I denne artikkelen vil vi beskrive detaljene.
Gitt: et Þkosystem og et API-portal med et grensesnitt, hvor brukerne er registrert, fÄr informasjon osv. Vi mÄ lage en brukervennlig og pÄlitelig API Gateway. I prosessen mÄtte vi sikre
- registrering,
- kontroll av tilkoblinger til API,
- overvÄking av hvordan brukerne bruker det endelige systemet,
- behandling av forretningsindikatorer.

I artikkelen vil vi dele vÄr erfaring med Ä lage API Gateway, hvor vi lÞste fÞlgende oppgaver:
- autentisering av brukeren,
- autorisering av brukeren,
- modifisering av den opprinnelige forespĂžrselen,
- proxying av forespĂžrselen,
- etterbehandling av svaret.
Det finnes to typer API-hÄndtering:
1. Standard, som fungerer pÄ fÞlgende mÄte. FÞr tilkoblingen tester brukeren mulighetene, deretter betaler han og integrerer pÄ sin nettside. Dette brukes oftest av smÄ og mellomstore bedrifter.
2. Stor B2B API Management, der selskapet fÞrst tar en forretningsbeslutning om tilkobling, blir partner med selskapskontrakt, fÞr de kobles til API. Etter Ä ha ordnet alle formaliteter fÄr selskapet testtilgang, gjennomgÄr testing og gÄr i produksjon. Men dette er ikke mulig uten ledelsesvedtak om tilkobling.

VÄr lÞsning
I denne delen vil vi fortelle om opprettelsen av API Gateway.
Sluttbrukerne av den opprettede API-gatewayen er partnere av vÄr kunde. For hver av dem har vi allerede lagret de nÞdvendige kontraktene. Vi mÄ bare utvide funksjonaliteten ved Ä merke den gitte tilgangen til gatewayen. Dermed trengs en kontrollert prosess for tilkobling og forvaltning.
SelvfÞlgelig kunne vi valgt en allerede eksisterende lÞsning for API Management og opprettelse av API Gateway spesielt. For eksempel kunne dette vÊrt. Dette passet oss ikke, fordi vi allerede hadde en API-portal og et stort Þkosystem bygget rundt den. Alle brukere var allerede registrert, de forsto allerede hvor og hvordan de kunne fÄ den informasjonen de trengte. API-portalen hadde allerede de nÞdvendige grensesnittene, vi hadde bare behov for en API Gateway. Egentlig var det utviklingen av den vi begynte Ä fokusere pÄ.
Det vi kaller API Gateway er en slags proxy. Her hadde vi igjen et valg â vi kunne skrive vĂ„r egen proxy, eller velge noe ferdig. I dette tilfellet valgte vi den andre veien og gikk for en kombinasjon av nginx+Lua. Hvorfor? Vi trengte pĂ„litelig, testet programvare som stĂžtter skalering. Vi Ăžnsket ikke Ă„ sjekke bĂ„de forretningslogikkens korrekthet og proxyens funksjonalitet etter implementasjonen.
Hver webserver har en behandlingspipeline for forespĂžrselen. I tilfelle av nginx ser den slik ut:

(skjema fra )
MÄlet vÄrt var Ä integrere oss i denne pipelinen pÄ det punktet hvor vi kan modifisere den originale forespÞrselen.
Vi Þnsker Ä lage en transparent proxy, slik at forespÞrselen forblir den samme som nÄr den kom inn. Vi kontrollerer bare tilgangen til den endelige API-en, og hjelper forespÞrselen med Ä nÄ frem til den. Hvis forespÞrselen er feil, skal den endelige API-en vise feilen, ikke vi. Den eneste grunnen til at vi kan avvise en forespÞrsel er mangel pÄ tilgang for klienten.
For nginx eksisterer det allerede En funksjon har blitt . Lua er et skriptsprÄk, det er svÊrt lettvekts og enkelt Ä lÊre. Dermed implementerte vi den nÞdvendige logikken med hjelp av Lua.
Konfigurasjonen av nginx (analog med ruteapplikasjonen), der alt arbeidet utfĂžres, er ganske forstĂ„elig. Den siste direktiven â post_action â er bemerkelsesverdig.
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;
}
La oss se hva som skjer i denne konfigurasjonen:
more_clear_input_headers â renser verdien angitt etter direktivet for overskrifter.
lua_need_request_body â regulerer om den originale forespĂžrselens kropp skal leses fĂžr direktivene rewrite/access/access_by_lua utfĂžres eller ikke. Som standard leser ikke nginx forespĂžrselens kropp, og hvis du trenger tilgang til den, mĂ„ denne direktiven settes til on.
rewrite_by_lua_file â sti for skrift, der beskriver logikken for Ă„ modifisere forespĂžrselen
access_by_lua_file â sti for skriptet som inneholder logikken som sjekker om det er tilgang til ressursen.
proxy_pass â url-en som forespĂžrselen vil bli proxyert til.
body_filter_by_lua_file â sti for skriptet som inneholder logikken for filtrering av forespĂžrselen fĂžr den returneres til klienten.
Og til slutt, post_action â en offisielt udokumentert direktiv som kan brukes til Ă„ utfĂžre flere handlinger etter at svaret er gitt til klienten.
Deretter skal vi forklare i rekkefÞlge hvordan vi lÞste vÄre oppgaver.
Autorisasjon/autentisering og modifisering av forespĂžrselen
Autorisering
Vi bygde autorisasjonen og autentiseringen ved hjelp av tilgang basert pÄ sertifikat. Det er et rotsertifikat. Hver ny kunde av kunden fÄr sitt eget personlige sertifikat, som gir dem tilgang til API-en. Dette sertifikatet konfigureres i server-delen av nginx-innstillingene.
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;Modifisering
Det kan stilles et rettferdig spÞrsmÄl: hva skal vi gjÞre med sertifiserte kunder hvis vi plutselig Þnsker Ä frakoble dem fra systemet? Skal vi ikke forny sertifikatene for alle de andre kundene?
Slik har vi smidig kommet til neste oppgave â modifisering av den opprinnelige forespĂžrselen. Den opprinnelige forespĂžrselen fra kunden er ikke gyldig for det endelige systemet. En av oppgavene er Ă„ legge til manglende deler i forespĂžrselen for Ă„ gjĂžre den gyldig. Poenget er at de manglende dataene er forskjellige for hver kunde. Vi vet at kunden kommer til oss med et sertifikat, fra hvilket vi kan ta et fingeravtrykk og hente de nĂždvendige kundedataene fra databasen.
Hvis det pÄ et tidspunkt blir nÞdvendig Ä frakoble kunden fra vÄr tjeneste, vil dataene deres forsvinne fra databasen, og de vil ikke kunne gjÞre noe.
HÄndtering av kundedata
Vi mÄtte sikre hÞy tilgjengelighet av lÞsningen, spesielt for hvordan vi henter kundedataene. Utfordringen er at den primÊre kilden til disse dataene er en tredjepartstjeneste som ikke garanterer pÄlitelig og tilstrekkelig hÞy hastighet.
Derfor mÄtte vi sikre hÞy tilgjengelighet for kundedataene. Som verktÞy valgte vi , som gir oss:
- raskap for data,
- mulighet til Ä organisere en klynge av flere noder med replikerte data pÄ forskjellige noder.
Vi fulgte den enkleste strategien for datalevering til cache:

Samarbeid med det endelige systemet skjer innenfor sesjoner, og det er en grense for det maksimale antallet. Hvis kunden ikke har lukket sesjonen, mÄ vi gjÞre det.
Data om Äpne sesjoner kommer fra det endelige systemet og behandles fÞrst pÄ Lua-siden. Vi bestemte oss for Ä bruke Hazelcast for Ä lagre disse dataene med en jobb skrevet i .NET. Deretter sjekker vi regelmessig livsretten til Äpne sesjoner og stenger utgÄtte.
Tilgang til Hazelcast bÄde fra Lua og .NET
Det finnes ingen Lua-klienter for Ä jobbe med Hazelcast, men Hazelcast har et REST API, som vi valgte Ä bruke. For .NET er det , som vi planla Ä bruke for Ä fÄ tilgang til dataene fra Hazelcast pÄ .NET-siden. Men slik gikk det ikke.

Ved lagring av data gjennom REST og uthenting via .NET-klienten brukes forskjellige serializator-deserializatorer. Derfor er det umulig Ă„ legge inn data via REST og hente dem ut via .NET-klienten og omvendt.
Hvis det er interesserte, kan vi fortelle mer om dette problemet i en egen artikkel. Spoiler â pĂ„ diagrammet.

Logging og overvÄking
VĂ„r bedriftsstandard for logging via .NET â Serilog, alle logger havner til slutt i Elasticsearch, og analysen foregĂ„r via Kibana. Noe lignende Ăžnsket vi Ă„ gjĂžre i dette tilfellet. Den eneste som ble funnet for Ă„ jobbe med Elastic pĂ„ Lua, krasjet ved fĂžrste require. Og vi brukte Fluentd.
â en open source-lĂžsning for Ă„ gi et samlet lag av applikasjonslogging. Den lar oss samle logger fra ulike nivĂ„er av applikasjonen, og deretter videresende dem til en enhetlig kilde.
API Gateway kjÞrer i K8S, sÄ vi bestemte oss for Ä legge til en container med fluentd i samme pod, for Ä skrive logger til den eksisterende Äpne tcp-porten til fluentd.
Vi undersÞkte ogsÄ hvordan fluentd ville oppfÞre seg hvis den ikke hadde forbindelse med Elasticsearch. I lÞpet av to dager ble det kontinuerlig sendt forespÞrsel til gatewayen, logger ble sendt til fluentd, men IP-adressen til Elastic ble blokkert. Etter at forbindelsen ble gjenopprettet, slapp fluentd ut absolutt alle logger til Elastic.
Konklusjon
Den valgte tilnÊrmingen for implementering gjorde at vi klarte Ä levere et fullt fungerende produkt i produksjonsmiljÞet pÄ bare 2,5 mÄneder.
Hvis du noen gang mÄ hÄndtere lignende ting, anbefaler vi fÞrst og fremst Ä tydelig forstÄ hvilken oppgave du lÞser og hvilke ressurser du allerede har. VÊr oppmerksom pÄ utfordringene med integrering med eksisterende API-styringssystemer.
SkjĂžnn for deg selv hva nĂžyaktig du planlegger Ă„ utvikle â bare forretningslogikken for Ă„ behandle forespĂžrslene eller, som det kan ha vĂŠrt i vĂ„rt tilfelle, hele proxyen. Ikke glem at alt du gjĂžr selv, mĂ„ testes grundig etterpĂ„.
Kilde: habr.com
