Asigurarea API-ului Web ASP.NET

Odată ce ați dezvoltat API-ul Web, înainte de a le expune clienților dvs., pe baza nevoilor dvs., este posibil să aveți nevoie să asigurați unele sau toate părțile din Serviciul API, astfel încât numai utilizatorii verificați să poată accesa serviciul dvs. API. Această securizare în ASP.NET poate fi realizată utilizând mecanismele de autentificare și autorizare.

Autentificare

Autentificarea este procesul de a determina dacă cineva sau ceva este, de fapt, cine sau ce se pretinde a fi. Prin utilizarea mecanismului de autentificare, ne asigurăm că fiecare solicitare primită de către serviciul API Web este trimisă de la un client cu acreditări corespunzătoare.

Autentificarea utilizând Handlers

A gestionarea mesajelor este o clasă care primește o solicitare HTTP și returnează un răspuns HTTP. Instrumentele de gestionare a mesajelor sunt clase derivate din clasa abstractă HttpMessageHandler. Ele sunt bune pentru preocupările transversale care funcționează la nivelul mesajelor HTTP (mai degrabă decât acțiunile controlerului). De exemplu, un manipulator de mesaje ar putea:

  • citiți sau modificați antetele de solicitare
  • adăugați un antet de răspuns la răspunsuri
  • validați cererile înainte de a ajunge la controlor

Într-un API Web, de obicei, o serie de agenți de procesare a mesajelor sunt înlănțuiți împreună, formând un model numit delegarea manipulant.

Ordinea în care sunt configurați aceste dispozitive de manipulare este importantă, deoarece acestea vor fi executate secvențial. 

Cel mai important handler se află la vârf, păstrând tot ceea ce vine. Dacă cecurile trec, acesta va transmite această cerere în lanț către următorul operator de delegare și așa mai departe. 

Dacă totul merge bine, va ajunge apoi la controlerul API și va executa acțiunea dorită. Cu toate acestea, în cazul în care oricare dintre verificări eșuează în cadrul procesatorilor, cererea este respinsă și răspunsul este trimis clientului.

Cu această multă teorie în mână, acum să scriem cod pentru manipulatorii noștri. Vom crea doi agenți de gestionare a mesajelor în acest articol:

  1. APIKeyHandler: Handlerul responsabil pentru interceptarea unei cereri HTTP și asigurarea antetului său conține o cheie API
  2. AuthHandler: Handler responsabil pentru autentificarea acreditărilor și a rolurilor utilizatorilor

API-cheie de autentificare

În proiectul dvs. Web API, creați un dosar numit MessageHandlersși adăugați o clasă APIKeyHandler.cs.

clasa publică APIKeyHandler: DelegatingHandler // setați o cheie prestabilită implicită a contului API yourApiKey = "X-some-key"; Protecție async cu suprascriere protejată SendAsync (solicitarea HttpRequestMessage, CancellationToken cancellationToken) bool isValidAPIKey = false; IEnumerable lsHeaders; // Validați că tasta api există var checkApiKeyExists = request.Headers.TryGetValues ​​("API_KEY", out lsHeaders); dacă (checkApiKeyExists) if (lsHeaders.FirstOrDefault () este egal (yourApiKey)) isValidAPIKey = true;  // Dacă cheia nu este validă, returnați un cod de stare http. dacă (! isValidAPIKey) returnează request.CreateResponse (HttpStatusCode.Forbidden, "Bad API Key"); // Permiteți cererii să proceseze în continuare conducta var răspuns = await base.SendAsync (request, cancelToken); // Întoarceți răspunsul înapoi la răspunsul înapoi al lanțului; 

APIKeyHandler.cs moștenește de la DelegatingHandler, care la rândul ei moștenește HttpMessageHandler. Acest lucru ne permite să ignorăm funcționalitatea pentru inspectarea unei solicitări HTTP și să controlam dacă vrem să permitem ca această solicitare să curgă în jos pe conductă la mâna și controlerul următor sau să oprească solicitarea prin trimiterea unui răspuns personalizat.

În această clasă, realizăm acest lucru prin suprimarea SendAsync metodă. Această metodă caută o cheie API (API_KEY) în antetul fiecărei solicitări HTTP și transmite cererea către controler numai dacă există o cheie API valabilă în antetul solicitării.

Acum, pentru a vedea acest manipulant în acțiune, trebuie să îl înregistrăm mai întâi la cererea noastră în Application_Start metoda de la Global.asax fişier.

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

Încercați să apelați orice metodă pe care ați expus-o prin intermediul controlerelor Web API și ar trebui să vedeți ca răspuns "Cheia API-ului rău".

Pentru o demonstrație în acest articol, folosesc același proiect și adresele URL pe care le-am creat în articolul meu anterior "Dezvoltarea unui API Web ASP.NET".

Să verificăm dacă APIKeyHandlerfuncționează bine, prin crearea unei solicitări HTTP cu anteturi corecte. Pentru aceasta, trebuie să creați un antet HTTP cu valoarea cheie:

"API_KEY": "X-some-key"

Folosesc un plugin de browser Mozilla numit "Instrumentul HTTP" pentru crearea antetelor de cerere HTTP aici.

Cererea HTTP este acum trecută până la controler de către handler.

Deci, handler-ul nostru de verificare a cheilor API este în vigoare acum. Aceasta asigură API-ul Web pentru a vă asigura că numai acei clienți care au chei API valide pot accesa acest serviciu. În continuare vom analiza modul în care putem implementa securitatea bazată pe rolurile utilizatorilor.

Autentificare de bază

Autentificarea de bază, așa cum sugerează și numele acesteia, este cea mai simplă și de bază formă de autentificare a cererilor HTTP. Clientul trimite acreditările codate Base64 în antetul Autorize la fiecare solicitare HTTP și numai dacă acreditările sunt verificate, API-ul returnează răspunsul așteptat. Autentificarea de bază nu necesită stocarea pe sesiuni de pe server sau implementarea cookie-urilor, deoarece fiecare cerere este verificată de API.

Odată ce se va înțelege implementarea autentificării de bază în API-ul Web, va fi foarte ușor să creezi alte forme de autentificare. Doar procesul de autentificare va fi diferit, iar interfața Web API, în cazul în care se face, va fi aceeași.

Pentru a verifica acreditările utilizatorilor, creăm un IPrincipal obiect care reprezintă contextul de securitate actual.

Adăugați un nou dosar numit Securitate și o nouă clasă TestAPIPrincipal.cs în ea.

clasa publica TestAPIPincipal: IPrincipal // Constructor public TestAPIPiprimcipal (string userName) UserName = userName; Identity = noua genericIdentity (userName);  șir public Nume utilizator get; a stabilit;  public IIdentity Identity get; a stabilit;  bool public IsInRole (rol de coardă) if (role.Equals ("user")) return true;  altfel return false; 

IIdentity obiect asociat cu principalul are o proprietate numită IsAuthenticated. Dacă utilizatorul este autentificat, această proprietate va reveni la adevărat; în caz contrar, va reveni fals.

Acum, hai să creăm un alt handler numit AuthHandler.cs.

clasa publică AuthHandler: DelegatingHandler string _userName = ""; // Metoda de validare a acreditărilor din Autorizare // Valoarea headerului privat bool ValidateCredentials (AuthenticationHeaderValue authenticationHeaderVal) încercați if (authenticationHeaderVal! = Null &&! String.IsNullOrEmpty (authenticationHeaderVal.Parameter)) string [] decodedCredentials = Encoding.ASCII.GetString (Convert.FromBase64String (autentificareHeaderVal.Parametru)) .Split (nou [] ':'); // now decodedCredentials [0] va conține // username și decodedCredentials [1] va // conține parola. dacă (decodedCredentials [0] .Equals ("username") && decodedCredentials [1] .Equals ("parola")) _userName = "John Doe"; return true; // request authenticated.  return false; // cererea nu a fost autentificată.  catch return false;  sarcină async protejată SendAsync (solicitare HttpRequestMessage, CancellationToken cancellationToken) // dacă acreditările sunt validate, // setați CurrentPrincipal și Current.User dacă (ValidateCredentials (request.Headers.Authorization)) Thread.CurrentPrincipal = new TestAPIPprincipal (_userName); HttpContext.Current.User = nou TestAPIPincipal (_userName);  // Executați base.SendAsync pentru a executa acțiunile implicite // și după ce a fost finalizată, // capturați obiectul răspuns și adăugați // antet WWW-Authenticate dacă cererea // a fost marcată ca neautorizată. // Permiteți cererii să proceseze în continuare conducta var răspuns = await base.SendAsync (request, cancelToken); dacă (răspuns.StatusCode == HttpStatusCode.Unauthorized &&! response.Headers.Contains ("WwwAuthenticate")) răspuns.Headers.Add ("WwwAuthenticate", "Basic");  retur răspuns; 

Această clasă conține o metodă privată ValidateCredentials, care verifică pentru valorile de nume de utilizator și parola decodate din antetul HTTP al solicitării și de asemenea SendAsyncpentru interceptarea solicitării HTTP.

Dacă acreditările clientului sunt valide, atunci actualul IPrincipalobiect este atașat la firul curent, adică. Thread.CurrentPrincipal. Am setat și HttpContext.Current.User pentru a face coerența contextului de securitate. Acest lucru ne permite să accesăm detaliile utilizatorului curent de oriunde din aplicație.

Odată ce cererea este autentificată, base.SendAsync este chemat să trimită cererea la dispozitivul de manipulare internă. Dacă răspunsul conține un antet HTTP neautorizat, codul injectează a WwwAuthenticate antet cu valoarea De bazăpentru a informa clientul că serviciul nostru așteaptă autentificarea de bază.

Acum, trebuie să înregistrăm acest handler în Global.asax clasa pe care am făcut-o pentru noi ApiKeyHandler. Asigurați-vă că AuthHandlerhandler este mai jos de înregistrare primul handler pentru a vă asigura de ordinea corectă.

GlobalConfiguration.Configuration.MessageHandlers.Add (nou APIKeyHandler ()); GlobalConfiguration.Configuration.MessageHandlers.Add (noul AuthHandler ());

Dar înainte de a putea vedea autentificarea de bază în acțiune, va trebui mai întâi să implementăm autorizația.

Autorizare

Autorizarea verifică dacă utilizatorul autentificat poate efectua o anumită acțiune sau poate consuma o anumită resursă. Acest proces în API Web se întâmplă mai târziu în conductă, după
autentificare și înainte ca acțiunile controlerului să fie executate.

Utilizând atributul de autorizare

ASP.NET MVC Web API oferă un filtru de autorizare numit AuthorizeAttributecare verifică cererea IPrincipal, verifică Identity.IsAuthenticated proprietate și returnează a 401 Neautorizat Starea HTTP dacă valoarea este falsă și metoda de acțiune solicitată nu va fi executată. Acest filtru poate fi aplicat în diferite niveluri, cum ar fi nivelul controlerului sau nivelul de acțiune și poate fi aplicat cu ușurință utilizând [Autoriza]sintaxa în partea de sus a controlorilor sau a acțiunilor.

[Autorizați] public Class ClassifiedsController: ApiController

Odată ce acest atribut este setat, acesta va împiedica accesul tuturor metodelor de acțiune din controler de către utilizatori neautorizați.

Mai întâi manipulatorul nostru de autentificare de bază începe să stabilească identitatea curentă a utilizatorului IPrincipal obiect. Apoi, înainte ca această solicitare să ajungă la controler, AuthorizeAttribute verifică accesul la controlerul / acțiunea particulară pentru utilizatorul curent.

Pentru a vedea acest lucru în acțiune, mai întâi să creăm o solicitare HTTP fără acreditările corespunzătoare.

Accesul este refuzat de către AuthorizeAttribute.

Acum, să creăm o altă solicitare cu cheia / valoarea antetului de autorizare de data aceasta, după cum urmează:

Autorizare: De bază dXNlcm5hbWU6cGFzc3dvcmQ =

Aici, valoarea dXNlcm5hbWU6cGFzc3dvcmQ =esteFormular codat Base64 din nume utilizator, parola.

Această solicitare are drepturi de acces la controler / acțiune așa cum era de așteptat.

Acesta este un exemplu de asigurare a acțiunilor publice ale întregului controler.

Acțiune la nivel de acțiune

De asemenea, putem restricționa unele părți ale acțiunilor controlerului prin setarea[Autoriza] atribut la nivel de acțiune numai în loc. Acest lucru ne va permite să avem atât acțiuni protejate, cât și acțiuni neprotejate în același controler.

// [Autorizați] public Class ClassifiedsController: ApiController public List Obțineți (id șir) return ClassifiedService.GetClassifieds (id);  [Autorizați] Lista publică Obțineți () returnate ClassifiedService.GetClassifieds (""); 

Atributul [AllowAnonymous]

O altă modalitate de a avea atât acțiuni protejate cât și acțiuni neprotejate în cadrul controlorului este prin utilizarea [AllowAnonymous] atribut. Când am setat [Autoriza] atribut la nivelul controlerului și setați [AllowAnonymous] atribut pentru orice acțiune din interiorul controlerului, acea acțiune va sări peste [Autoriza] atribut.

Controlul rolurilor și al utilizatorilor

De asemenea, este posibil să filtrați anumite roluri și utilizatori pentru drepturi de acces. De exemplu, putem avea ceva de genul [Autorizați (roluri = "Admin")] pe controlere și acțiuni.

Atribut de autorizare personalizat

În cele din urmă, putem crea, de asemenea, propriul atribut de autorizare personalizată, în funcție de nevoile noastre. Una dintre modalitățile de a realiza acest lucru este extinderea AuthorizeAttribute.

Spuneți că dorim să restricționăm serviciul nostru API Web numai pentru anumite părți ale lumii, prin restricționarea accesului la utilizatorii care nu se află într-un anumit interval de adresă IP. Putem crea un atribut personalizat de autorizare în acest scop, derivând din AuthorizeAttributeclasa și suprascrierea IsAuthorized metodă.

clasa publica RestrictIPsAttribute: System.Web.Http.AuthorizeAttribute boot override boole IsAuthorized (context HttpActionContext) var ip = HttpContext.Current.Request.UserHostAddress; // verifica ip aici dacă (ip.Contains ("")) return true;  return false; 

Odată ce avem atributul personalizat de autorizare, putem decora controlorii / acțiunile cu el.

[RestrictIPsAttribute] Listă publică Obțineți () returnate ClassifiedService.GetClassifieds (""); 

Concluzie

În acest articol, ne-am uitat la modul în care putem asigura serviciul nostru API Web ASP.NET înainte de a expune serviciul la lumea din afara. Am analizat modul în care putem autentifica cererile HTTP pentru chei API valide și pentru acreditările valide pentru utilizatori. Cu această cunoaștere în mână, cred că suntem gata să dezvoltăm orice securitate personalizată pentru API-urile noastre.

Pentru cei care sunteți fie doar începători cu Laravel, fie căutați să vă extindeți cunoștințele, site-ul sau aplicația cu extensii, avem o varietate de lucruri pe care le puteți studia în piața Envato.

Sper că te-ai bucurat de lectură la fel de mult ca și învățarea din acest articol și nu uitați să lăsați orice întrebări sau comentarii în feed-ul de mai jos!

Cod