În ultima lună, am avut șansa să implementez autentificarea JWT pentru un proiect secundar. Am lucrat anterior cu JWT în Ruby on Rails, dar aceasta a fost prima dată în primăvară.

În această postare, voi încerca să explic ceea ce am învățat și aplicat în proiectul meu pentru a împărtăși experiența mea și, sperăm, să ajut unii oameni.

Vom începe prin a arunca o privire rapidă asupra teoriei din spatele JWT și a modului în care funcționează. Apoi vom analiza cum să-l implementăm într-o aplicație Spring Boot.

JWT Noțiuni de bază

JWT sau JSON Web Jeton (RFC 7519), este un standard utilizat în cea mai mare parte pentru securizarea API-urilor REST. În ciuda faptului că este o tehnologie relativ nouă, câștigă popularitate rapidă.

În procesul de autentificare JWT, front-end-ul (clientul) trimite mai întâi câteva acreditări pentru a se autentifica (nume de utilizator și parolă în cazul nostru, deoarece lucrăm la o aplicație web).

ad-banner

Serverul (aplicația Spring în cazul nostru) verifică apoi acele acreditări și, dacă acestea sunt valide, generează un JWT și îl returnează.

După acest pas, clientul trebuie să furnizeze acest simbol în cerere Autorizare antet în forma „Bearer TOKEN”. Back-end-ul va verifica validitatea acestui simbol și va autoriza sau respinge cererile. Jetonul poate, de asemenea, să stocheze rolurile utilizatorilor și să autorizeze cererile pe baza autorităților date.

Cum se configureaza Java Spring Boot JWT Autorizare si autentificare

Implementare

Acum să vedem cum putem implementa mecanismul de conectare și salvare JWT într-o aplicație reală de primăvară.

Dependențe

Puteți vedea lista dependențelor Maven pe care exemplul nostru de cod le folosește mai jos. Rețineți că dependențele de bază precum Spring Boot și Hibernate nu sunt incluse în această captură de ecran.

Cum se configureaza Java Spring Boot JWT Autorizare si autentificare

Salvarea utilizatorilor

Vom începe prin a crea controlere pentru a salva utilizatorii în siguranță și a le autentifica pe baza numelui de utilizator și a parolei.

Avem o entitate model numită Utilizator. Este o clasă de entitate simplă care se mapează la UTILIZATOR masa. Puteți utiliza orice proprietăți de care aveți nevoie în funcție de aplicația dvs.

1611670507 466 Cum se configureaza Java Spring Boot JWT Autorizare si autentificare

Avem, de asemenea, un simplu UserRepository clasa pentru a salva utilizatorii. Trebuie să trecem peste findByUsername metodă, deoarece o vom folosi în autentificare.

public interface UserRepository extends JpaRepository<User, String>{ 
    User findByUsername(String username); 
}

Nu ar trebui să stocăm niciodată parole cu text clar în baza de date, deoarece mulți utilizatori tind să folosească aceeași parolă pentru mai multe site-uri.

Există mulți algoritmi de hash diferiți, dar cel mai frecvent utilizat este BCrypt și este o metodă recomandată de hash securizat. Puteți verifica acest articol pentru mai multe informații despre subiect.

Pentru a hash parola, vom defini un BCrypt bob în @SpringBootApplication și adnotați clasa principală după cum urmează:

@Bean public BCryptPasswordEncoder bCryptPasswordEncoder() {
    return new BCryptPasswordEncoder(); 
}

Vom apela metodele de pe acest bean când vom avea nevoie de o parolă.

De asemenea, avem nevoie de un UserController pentru a salva utilizatorii. Creăm controlerul, îl adnotăm cu @RestController, și definiți maparea corespunzătoare.

În aplicația noastră, salvăm utilizatorul pe baza unui obiect DTO care este transmis din partea frontală. De asemenea, puteți trece un obiect User în @RequestBody.

După ce trecem obiectul DTO, criptăm câmpul de parolă folosind BCrypt bob pe care l-am creat mai devreme. Puteți face acest lucru și în controler, dar este o practică mai bună să puneți această logică în clasa de servicii.

@Transactional(rollbackFor = Exception.class) 
public String saveDto(UserDto userDto) { 
    userDto.setPassword(bCryptPasswordEncoder
           .encode(userDto.getPassword())); 
    return save(new User(userDto)).getId(); 
}

Filtru de autentificare

Avem nevoie de autentificare pentru a ne asigura că utilizatorul este cu adevărat cine pretinde că este. Vom folosi perechea clasică de nume de utilizator / parolă pentru a realiza acest lucru.

Iată pașii pentru implementarea autentificării:

  1. Creați filtrul nostru de autentificare care se extinde UsernamePasswordAuthenticationFilter
  2. Creați o clasă de configurare de securitate care se extinde WebSecurityConfigurerAdapter și aplicați filtrul

Iată codul pentru filtrul nostru de autentificare – după cum știți, filtrele reprezintă coloana vertebrală a Spring Security.

Să trecem peste acest cod pas cu pas.

Această clasă se extinde UsernamePasswordAuthenticationFilter care este clasa implicită pentru autentificarea parolei în Spring Security. Îl extindem pentru a defini logica noastră de autentificare personalizată.

Facem un apel către setFilterProcessesUrl metodă în constructorul nostru. Această metodă setează adresa URL de autentificare implicită la parametrul furnizat.

Dacă eliminați această linie, Spring Security creează fișierul “/Autentificare” punct final în mod implicit. Acesta definește punctul final de conectare pentru noi, motiv pentru care nu vom defini în mod explicit un punct final de conectare în controlerul nostru.

După această linie, punctul nostru final de conectare va fi / api / services / controller / user / login. Puteți utiliza această funcție pentru a rămâne în concordanță cu obiectivele dvs. finale.

Înlocuim tryAuthentication și Autentificare de succes metode ale UsernameAuthenticationFilter clasă.

tryAuthentication funcția se execută atunci când utilizatorul încearcă să se conecteze la aplicația noastră. Citește acreditările, creează un utilizator POJO din acestea, apoi verifică acreditările pentru autentificare.

Trecem numele de utilizator, parola și o listă goală. Lista goală reprezintă autoritățile (rolurile) și o lăsăm așa cum este, deoarece nu avem încă niciun rol în aplicația noastră.

Dacă autentificarea are succes, Autentificare de succes rulează metoda. Parametrii acestei metode sunt trecuți de Spring Security în culise.

tryAuthentication metoda returnează un Autentificare obiect care conține autoritățile pe care le-am trecut în timp ce încercam.

Vrem să returnăm un jeton utilizatorului după ce autentificarea are succes, așa că creăm jetonul folosind numele de utilizator, secretul și data de expirare. Trebuie să definim SECRET și DATA EXPIRĂRII acum.

Creăm o clasă care să fie un container pentru constantele noastre. Puteți seta secretul pentru orice doriți, dar cea mai bună practică este să creați cheia secretă atâta timp cât aveți hash. Noi folosim HS256 algoritm din acest exemplu, deci cheia noastră secretă este de 256 de biți / 32 de caractere.

Timpul de expirare este setat la 15 minute, deoarece este cea mai bună practică împotriva atacurilor secrete cu forță brută. Timpul este în milisecunde.

Am pregătit filtrul nostru de autentificare, dar nu este încă activ. De asemenea, avem nevoie de un filtru de autorizare și apoi le vom aplica pe amândouă printr-o clasă de configurație.

Acest filtru va verifica existența și validitatea jetonului de acces în antetul de autorizare. Vom specifica ce puncte finale vor fi supuse acestui filtru în clasa noastră de configurație.

Filtru de autorizare

doFilterInternal metoda interceptează solicitările, apoi verifică antetul de autorizare. Dacă antetul nu este prezent sau nu începe cu „BEARER”, acesta trece la lanțul de filtrare.

Dacă antetul este prezent, getAuthentication se invocă metoda. getAuthentication verifică JWT și, dacă jetonul este valid, returnează un jeton de acces pe care Spring îl va folosi intern.

Acest nou jeton este apoi salvat în SecurityContext. De asemenea, puteți trece în Autorități la acest simbol dacă aveți nevoie de autorizare bazată pe roluri.

Filtrele noastre sunt gata și acum trebuie să le punem în acțiune cu ajutorul unei clase de configurare.

Configurare

Adnotăm această clasă cu @EnableWebSecurity și extindeți WebSecurityConfigureAdapter pentru a implementa logica noastră de securitate personalizată.

Autocablăm bobul BCrypt pe care l-am definit mai devreme. De asemenea, conectăm automat UserDetailsService pentru a găsi contul utilizatorului.

Cea mai importantă metodă este cea care acceptă un HttpSecurity obiect. Aici specificăm punctele finale și filtrele sigure pe care dorim să le aplicăm. Configurăm CORS și apoi permitem toate cererile de postare la adresa URL de înscriere pe care am definit-o în clasa constantelor.

Puteți adăuga alte potriviri de furnici pentru a le filtra pe baza modelelor și rolurilor URL și puteți Verifica această întrebare StackOverflow pentru exemple cu privire la asta. Cealaltă metodă configurează AuthenticationManager să utilizăm obiectul codificator ca codificator de parolă în timp ce verificăm acreditările.

Testarea

Să trimitem câteva solicitări pentru a testa dacă funcționează corect.

1611670507 913 Cum se configureaza Java Spring Boot JWT Autorizare si autentificare

Aici trimitem o solicitare GET pentru a accesa o resursă protejată. Serverul nostru răspunde cu un cod 403. Acesta este comportamentul așteptat deoarece nu am furnizat un jeton în antet. Acum să creăm un utilizator:

1611670507 142 Cum se configureaza Java Spring Boot JWT Autorizare si autentificare

Pentru a crea un utilizator, trimitem o solicitare de postare cu datele DTO ale utilizatorului nostru. Vom folosi acest utilizator pentru a vă conecta și a obține un jeton de acces.

1611670507 769 Cum se configureaza Java Spring Boot JWT Autorizare si autentificare

Grozav! Avem simbolul. După acest punct, vom folosi acest simbol pentru a accesa resursele protejate.

1611670507 825 Cum se configureaza Java Spring Boot JWT Autorizare si autentificare

Furnizăm jetonul în antetul de autorizare și acum ni se permite accesul la punctul nostru final protejat.

Concluzie

În acest tutorial v-am prezentat pașii pe care i-am făcut când am implementat autorizarea JWT și autentificarea parolei în primăvară. De asemenea, am învățat cum să salvăm un utilizator în siguranță.

Îți mulțumesc că ai citit – sper că ți-a fost de ajutor. Dacă sunteți interesat să citiți mai multe conținut de acest gen, nu ezitați să vă abonați la blogul meu la https://erinc.io. 🙂