Sikre ASP.NET Web API

Når du har utviklet web-API-en din, må du, før du eksponerer den for kundene dine, basert på dine behov, kanskje du må sikre noen eller alle deler av API-tjenesten din, slik at kun verifiserte brukere kan få tilgang til API-tjenesten din. Denne sikringen i ASP.NET kan oppnås ved hjelp av autentiserings- og autorisasjonsmekanismer.

Godkjenning

Autentisering er prosessen med å avgjøre om noen eller noe egentlig er hvem eller hva det hevdes å være. Ved å bruke godkjenningsmekanismen sørger vi for at alle forespørsler mottatt av web-API-tjenesten sendes fra en klient med riktig legitimasjon.

Autentisering ved hjelp av meldingshåndteringsprogrammer

EN meldingshåndterer er en klasse som mottar en HTTP-forespørsel og returnerer en HTTP-respons. Meldingshåndterer er avledede klasser fra abstrakt klassen HttpMessageHandler. De er gode for tverrgående bekymringer som opererer i nivå med HTTP-meldinger (i stedet for kontrollerhandlinger). For eksempel kan en meldingshåndterer:

  • les eller endre forespørselhodene
  • legg til en respons header for svar
  • validere forespørsler før de når kontrolleren

I en web-API, vanligvis, er en rekke meldingshåndterere koblet sammen, danner et mønster som heter delegere behandleren.

Ordren der disse håndteringene er satt opp er viktig da de vil bli utført i rekkefølge. 

Den viktigste handleren sitter helt øverst og beskytter alt som kommer inn. Hvis kontrollene passerer, vil det passere denne forespørselen ned i kjeden til neste delegerende handler, og så videre. 

Hvis alt går bra, kommer det da til API Controller og utfører ønsket handling. Men hvis noen av kontrollene feiler i håndteringsprogrammet, blir forespørselen nektet og et svar sendes til klienten.

Med denne mye teori i hånden, la oss nå skrive kode for våre håndtere. Vi vil opprette to meldingshåndterere i denne artikkelen:

  1. APIKeyHandler: Handler ansvarlig for å fange opp en HTTP-forespørsel og sikre hovedteksten inneholder en API-nøkkel
  2. AuthHandler: Handler ansvarlig for å autentisere brukerens legitimasjon og roller

Autentisering av API-nøkkel

I ditt Web API-prosjekt, opprett en mappe som heter MessageHandlersog legg til en klasse APIKeyHandler.cs.

offentlig klasse APIKeyHandler: DelegatingHandler // angi en standard API-nøkkel privat const-streng yourApiKey = "X-some-key"; beskyttet overstyring async oppgave SendAsync (HttpRequestMessage forespørsel, AvbestillingToken avbestillingToken) bool isValidAPIKey = false; IEnumerable lsHeaders; // Bekreft at api-nøkkelen eksisterer var checkApiKeyExists = request.Headers.TryGetValues ​​("API_KEY", ut lsHeaders); hvis (checkApiKeyExists) if (lsHeaders.FirstOrDefault (). Likestiller (yourApiKey)) isValidAPIKey = true;  // Hvis nøkkelen ikke er gyldig, returner du en http statuskode. hvis (! isValidAPIKey) returnere request.CreateResponse (HttpStatusCode.Forbidden, "Bad API Key"); // Tillat forespørselen å behandle ytterligere ned rørledningen var respons = vent base.SendAsync (forespørsel, kanselleringToken); // Gi tilbakemeldingen tilbake til tilbakekallingsresponsen; 

De APIKeyHandler.cs arver fra DelegatingHandler, som igjen arver fra HttpMessageHandler. Dette tillater oss å overstyre funksjonaliteten for å inspisere en HTTP-forespørsel og kontrollere om vi vil tillate denne forespørselen å flyte ned rørledningen til neste handler og kontroller eller stoppe forespørselen ved å sende et tilpasset svar.

I denne klassen oppnår vi dette ved å overstyre SendAsync metode. Denne metoden ser etter en API-nøkkel (API_KEY) i overskriften til hver HTTP-forespørsel, og sender forespørselen til kontrolleren bare hvis en gyldig API-nøkkel er tilstede i forespørselsoverskriften.

Nå, for å se denne handleren i aksjon, må vi først registrere den til vår søknad i Application_Start metode fra Global.asax fil.

GlobalConfiguration.Configuration.MessageHandlers.Add (ny APIKeyHandler ());

Prøv å ringe en hvilken som helst metode du har utsatt gjennom Web API-kontrollerne, og du bør se "Dårlig API-nøkkel" som svar.

For en demo i denne artikkelen bruker jeg det samme prosjektet og nettadressene som jeg har opprettet i min forrige artikkel, "Utvikling av en ASP.NET Web API".

La oss bekrefte at APIKeyHandlerFungerer i orden ved å lage en HTTP-forespørsel med riktige overskrifter. For det må vi opprette en HTTP-header med nøkkelverdi:

"API_KEY": "X-some-key"

Jeg bruker en Mozilla-nettleser-plugin kalt "HTTP-verktøy" for å lage HTTP-forespørselsoverskrifter her.

HTTP-forespørselen er nå bestått helt til kontrolleren av handleren.

Så vår API nøkkel kontroll håndterer er på plass nå. Dette sikrer vår web-API for å sikre at bare de klientene som er utstyrt med gyldige API-nøkler, kan få tilgang til denne tjenesten. Neste vil vi se på hvordan vi kan implementere sikkerhet basert på brukerroller.

Grunnleggende godkjenning

Grunnleggende godkjenning, som navnet antyder, er den mest enkle og grunnleggende formen for autentisering av HTTP-forespørsler. Klienten sender Base64-kodet legitimasjon i Autoriserings-header på hver HTTP-forespørsel, og bare hvis legitimasjonene er bekreftet, returnerer API-en den forventede responsen. Grunnleggende godkjenning krever ikke server-side økt lagring eller implementering av informasjonskapsler, da hver forespørsel er verifisert av API.

Når grunnleggende autentiseringsimplementering i Web API er forstått, vil det være veldig enkelt å koble andre former for godkjenning. Bare autentiseringsprosessen vil være annerledes, og Web API-kroker, der det er gjort, vil være det samme.

For å verifisere brukerens legitimasjon lager vi en IPrincipal objekt som representerer gjeldende sikkerhetskontekst.

Legg til en ny mappe som heter Sikkerhet og en ny klasse TestAPIPrincipal.cs i det.

offentlig klasse TestAPIPrincipal: IPrincipal // Constructor public TestAPIPrincipal (streng brukernavn) UserName = userName; Identity = new GenericIdentity (brukernavn);  offentlig streng Brukernavn get; sett;  offentlig identitetsidentitet get; sett;  offentlig bool IsInRole (strengrolle) if (role.Equals ("user")) return true;  ellers return false; 

De IIdentity objekt knyttet til rektor har en eiendom som kalles IsAuthenticated. Hvis brukeren er autentisert, vil denne egenskapen returnere sann; ellers vil den returnere falsk.

La oss nå opprette en annen handler som heter AuthHandler.cs.

offentlig klasse AuthHandler: DelegatingHandler string _userName = ""; // Metode for å validere legitimasjon fra autorisasjon // header verdi privat bool ValidateCredentials (AuthenticationHeaderValue authenticationHeaderVal) prøv if (authenticationHeaderVal! = Null &&! String.IsNullOrEmpty (authenticationHeaderVal.Parameter)) string [] decodedCredentials = Encoding.ASCII.GetString (Convert.FromBase64String (authenticationHeaderVal.Parameter)) .Split (ny [] ':'); // now decodedCredentials [0] vil inneholde // brukernavn og dekodetCredentials [1] vil // inneholde passord. hvis (dekodetCredensialer [0] .Ekvivalenter ("brukernavn") && dekodetCredensialer [1] .Ekvivalenter ("passord")) _userName = "John Doe"; return true; // request authenticated.  returnere falskt; // forespørsel ikke godkjent.  ta return false;  beskyttet tilsidesatt async-oppgave SendAsync (HttpRequestMessage request, AvbestillingToken cancellationToken) // hvis legitimasjonene er validert, // sett CurrentPrincipal og Current.User if (ValidateCredentials (request.Headers.Authorization)) Thread.CurrentPrincipal = ny TestAPIPrincipal (_userName); HttpContext.Current.User = nytt TestAPIPrincipal (_userName);  // Utfør base.SendAsync for å utføre standard // handlinger og når den er fullført, // fange svarobjektet og legg til // WWW-Authenticate header hvis forespørselen // var merket som uautorisert. // Tillat forespørselen å behandle ytterligere ned rørledningen var respons = vent base.SendAsync (forespørsel, kanselleringToken); hvis (response.StatusCode == HttpStatusCode.Unauthorized &&! response.Headers.Contains ("WwwAuthenticate")) response.Headers.Add ("WwwAuthenticate", "Basic");  returrespons; 

Denne klassen inneholder en privat metode ValidateCredentials, som sjekker for dekodert brukernavn og passordverdier fra HTTP-forespørselen, og også SendAsyncmetode for å fange HTTP-forespørselen.

Hvis legitimasjonene til klienten er gyldige, så gjeldende IPrincipalobjektet er festet til gjeldende tråd, dvs.. Thread.CurrentPrincipal. Vi satte også HttpContext.Current.User for å sikre sikkerhetskonteksten konsekvent. Dette tillater oss å få tilgang til den nåværende brukerens detaljer fra hvor som helst i applikasjonen.

Når forespørselen er autentisert, base.SendAsync kalles for å sende forespørselen til den interne handleren. Hvis svaret inneholder en HTTP uautorisert overskrift, sprer koden a WwwAuthenticate overskrift med verdien grunn~~POS=TRUNCå informere kunden om at vår tjeneste forventer grunnleggende godkjenning.

Nå må vi registrere denne handleren i Global.asax klasse som vi gjorde for vår ApiKeyHandler. Pass på at AuthHandlerHandler er under førstegangsregistrering for å forsikre seg om riktig rekkefølge.

GlobalConfiguration.Configuration.MessageHandlers.Add (ny APIKeyHandler ()); GlobalConfiguration.Configuration.MessageHandlers.Add (ny AuthHandler ());

Men før vi kan se grunnleggende godkjenning i aksjon, må vi først implementere autorisasjon.

Autorisasjon

Autorisasjon er å verifisere om den autentiserte brukeren kan utføre en bestemt handling eller konsumere en bestemt ressurs. Denne prosessen i Web API skjer senere i rørledningen, etterpå
autentisering og før kontrollerhandlingene utføres.

Bruk autoriseringsattributt

ASP.NET MVC Web API gir et autorisasjonsfilter kalt AuthorizeAttributesom bekrefter forespørselen IPrincipal, sjekker dens Identity.IsAuthenticated eiendom, og returnerer a 401 Uautorisert HTTP-status hvis verdien er feil, og den forespurte handlingsmetoden vil ikke bli utført. Dette filteret kan brukes på forskjellige nivåer som kontrollnivå eller handlingsnivå, og kan enkelt påføres ved hjelp av [Autorisere]syntaks på toppen av kontroller eller handlinger.

[Authorize] offentlig klasse ClassifiedsController: ApiController

Når dette attributtet er satt, vil det forhindre at alle handlinger i kontrollenheten blir åpnet av uautoriserte brukere.

Først begynner vår grunnleggende godkjenningshandler for å angi den nåværende brukerens identitet IPrincipal gjenstand. Så, før denne forespørselen når kontrolleren, AuthorizeAttribute verifiserer tilgangen til den aktuelle kontrolleren / handlingen for den nåværende brukeren.

For å se dette i aksjon, la vi først opprette en HTTP-forespørsel uten riktig legitimasjon.

Adgangen blir nektet av AuthorizeAttribute.

La oss nå lage en annen forespørsel med autorisasjonsoverskrift / verdi denne gangen på følgende måte:

Autorisasjon: Grunnleggende dXNlcm5hbWU6cGFzc3dvcmQ =

Her verdien dXNlcm5hbWU6cGFzc3dvcmQ =er denBase64-kodet form av brukernavn passord.

Denne forespørselen får tilgangsrettigheter til kontrolleren / handlingen som forventet.

Dette er et eksempel på å sikre hele kontrollerens offentlige handlinger.

Handlingsnivåautorisasjon

Vi kan også begrense enkelte deler av kontrolleringshandlingene ved å sette inn[Autorisere] Tilordne bare på handlingsnivået i stedet. Dette gjør at vi kan ha både beskyttede og ubeskyttede handlinger i samme kontroller.

// [Authorize] offentlig klasse ClassifiedsController: ApiController offentlig liste Få (streng-ID) return ClassifiedService.GetClassifieds (id);  [Authorize] offentlig liste Få () Return ClassifiedService.GetClassifieds (""); 

[AllowAnonymous] Attributt

En annen måte å ha både beskyttede og ubeskyttede handlinger i kontrolleren er ved å benytte seg av [AllowAnonymous] Egenskap. Når vi setter [Autorisere] attributt på kontrollnivå og sett inn [AllowAnonymous] Tilordne for enhver handling i kontrolleren, vil denne handlingen hoppe over [Autorisere] Egenskap.

Rolle og brukerkontroller

Det er også mulig å filtrere bestemte roller og brukere for tilgangsrettigheter. For eksempel kan vi ha noe sånn [Authorize (Roller = "Admin")] på kontroller og handlinger.

Tilpasset autorisasjonsattribut

Til slutt kan vi også lage vår egen tilpassede autorisasjonsattributt, avhengig av våre behov. En av måtene å oppnå dette er ved å utvide AuthorizeAttribute.

Si at vi ønsker å begrense vår web-API-tjeneste til bare visse deler av verden ved å begrense tilgangen til brukere som ikke er innenfor et visst utvalg av IP-adresser. Vi kan opprette et egendefinert autoriseringsattributt for dette formålet ved å hente fra AuthorizeAttributeklasse og overstyrer IsAuthorized metode.

offentlig klasse RestrictIPsAttribute: System.Web.Http.AuthorizeAttribute beskyttet overstyring bool IsAuthorized (HttpActionContext kontekst) var ip = HttpContext.Current.Request.UserHostAddress; // se etter ip her hvis (ip.Konnerer ("")) return true;  returner falsk; 

Når vi har vårt tilpassede godkjenningsattributt, kan vi dekorere våre kontrollører / handlinger med den.

[RestrictIPsAttribute] offentlig liste Få () Return ClassifiedService.GetClassifieds (""); 

Konklusjon

I denne artikkelen så vi på hvordan vi kan sikre vår ASP.NET Web API-tjeneste før du avslører tjenesten til verden utenfor. Vi så på hvordan vi kan godkjenne HTTP-forespørsler for gyldige API-nøkler og for gyldige brukeropplysninger. Med denne store kunnskapen i hånd, tror jeg vi er klare til å utvikle tilpasset sikkerhet for våre APIer.

For de av dere som enten bare er i gang med Laravel eller ser ut til å utvide din kunnskap, nettsted eller søknad med utvidelser, har vi en rekke ting du kan studere i Envato Market.

Jeg håper du likte å lese så mye som å lære fra denne artikkelen, og husk å legge igjen noen spørsmål eller kommentarer i feedet under!