Autentificare în React

O chestie care mă scoate din zona de confort la React e autentificarea, nu sunt foarte sigur cum s-o implementez fără să reinventez vreo roată :slight_smile: Poate îmi dați niște idei.

Fără să studiez prea mult, bănuiesc că aplicațiile React funcționează în general având partea de UI complet preîncărcată în browser, iar datele se încarcă/salvează de pe/pe server cu ajutorul unui REST API (probabil cu JSON), având în spate un backend oarecare.

Ca implementare propriu-zisă intuiesc un scenariu de felul următor:

  1. Se încarcă aplicația React de pe server. Momentan nu randăm nimic, că nu știm dacă suntem autentificați.

  2. Trimitem prin AJAX spre server un cookie sau un acces token oarecare (poate rezultat dintr-o folosire anterioară a aplicație din care am ieșit fără logout sau poate pur și simplu am dat refresh la pagină). Ca răspuns, serverul ne spune dacă suntem autentificați sau nu.

  3. Dacă NU suntem autentificați, aplicația React randează form-ul de login. După ce facem submit prin AJAX la user/pass, serverul ne dă OK-ul sau ne zice că am greșit credențialele. Dacă am primit OK-ul, randăm aplicația și ne vedem de treaba noastră.

  4. Dacă eram deja prea-autentificați nu se mai randează form-ul de login, trecem direct la treabă.

Ar mai fi o chestie, în timpul lucrului este posibil ca adminul să ne anuleze credențialele și atunci la primul request oarecare prin API backend-ul să ne informeze că ni s-a dat cu flit și să ne trimită înapoi la pagina de login.

Există vreun standard de facto în React pentru ce am descris mai sus? Ca backend ce se folosește de obicei dacă de exemplu vreau să am în spate MySQL? Preferința mea ar fi flask, din obișnuință. dar poate React se integrează mai bine cu nodejs? Sau nu are importanță?

Trebuie sa ai in considerare urmatoarele in procesul tau de gandire:

  1. Rutarea - ai rute care necesita sa fii autentificat sau chiar sa ai anumite permisiuni, cand dai de o ruta care are nevoie de sesiune de obicei trimiti la ruta cu formularul de login. Sunt mai multe librarii de routing, vezi react awesome pe github. Dar poți avea și pur și simplu componente care se randează sau nu în funcție de sesiune, elegant ar fi un hook useSession/useLogin.

  2. Provider-ul de permisiuni - este o componenta sus in aplicatia ta (HOC) care da prin Context sesiunea curenta (tenant-ul, permisiunile lui, cand expira), o alternativa la el e sa folosesti redux sau alt state global ca sa stochezi sesiunea. O solutie moderna e ori sa folosesti GraphQL si cu Apollo ai tot ce iti trebuie pentru autentificare, ori folosesti ceva ca token-query cu React Query , ori useSWR

  3. Aplicatia ta se bazeaza pe token-ul pe care il primeste si il salveaza clientul de la endpoint-ul de auth dupa ce utilizatorul a introdus userul si parola corecta (sau a confirmat identitatea cu SSO pe friendly name-ul tau). Acest token va fi trimis cu fiecare request, la fiecare serviciu si validat de server, poti sa folosesti ori un cookie, ori local storage ca sa il stochezi. Nu o sa zic direct JWT ca o sa imi sara oamenii in cap, cu JWT grija mare ce implementare folosesti.

  4. Serverul poate raspunde cu eroare de autentificare si asta va insemna ca se sterge token-ul curent din localstorage si se redirecteaza spre login form. Se pot face chestii mai real time cu websockets, long polling, event sourcing de pe server, graphql subscribe, fiecare solutie are avantaje si dezavantaje, in principal nu ai nevoie de real time fiindca orice trimite clientul il refuza serverul degeaba ai acces din UI. (o chestie faina ce poti sa faci e sa salvezi local state-ul inainte de a trimite un post spre server (sau iei state-ul din route-ul de dinainte, cu redux/zustand e foarte simplu) si il poti restaura dupa ce se logheaza din nou utilizatorul ca sa nu ramana cu mana goala dupa ce i-a expirat token-ul - adica sa ajunga inapoi unde era inainte sa i se ceara sa se autentifice din nou)

3 Likes

Da, interesant conceptul cu rutele protejate. De fapt trebuia să mă gândesc deja la asta, ca în flask folosesc un concept asemănător, la funcțiile rutelor care vreau să fie accesibile doar userilor autentificați le pun un decorator numit “login_required”.

Ca best practice, există în lumea React vreo preferință pentru platforma folosită pe backend? Ce folosește lumea?

Lumea foloseste sau migreaza spre GraphQL ca protocol de comunicare cu backend-ul iar pe backend de obicei e nodejs (cei de pe frontend sa poata faca si modificari la nevoie) dar orice limbaj cu support bun pentru GraphQL e ok.

Recomand cookie cu http only pentru ca este cel mai secure( nu are access js la el) dar browserul il trimite automat catre backend cu fiecare request.

Toate datele sunt aduse din backend, si tot acolo faci si verificarea daca este logat sau nu si intorci 401 sau 403 dupa caz.

2 Likes

Așa mă gândeam și eu, să nu-mi bat capul cu transmisia explicită a tokenului de autentificare.

Mi se pare extrem de complicat ce face tipul in videoclipul ala. Eu genul asta de aplicatie il rezolv din backend in Go cu un middleware folosind gorilla toolkit. Practic pot sa fac o multime de rute si subrute fiecare avand pe middleware ce vreau eu (logging, orice fel de autentificare, etc).

2 Likes

Da, nu e cel mai bun exemplu, vroiam doar sa arat solutia cu routing-ul.

Aici e mult mai frumos.

1 Like