This is an old revision of the document!
React.js este o bibliotecă JavaScript utilizată pentru crearea interfețelor utilizator web dinamice și interactive. A fost dezvoltată de Facebook și este folosită pentru construirea de aplicații web moderne. React.js este construită în jurul unui concept numit “componente”, care reprezintă bucăți de cod reutilizabile și independent gestionate, ceea ce face ca dezvoltarea aplicațiilor web să fie mai ușoară și mai eficientă.
Există mai multe motive pentru a folosi React.js în dezvoltarea aplicațiilor web. Iată câteva dintre cele mai importante:
React.js diferă față de alte framework-uri prin abordarea sa modulară și component-based. În timp ce alte framework-uri web se concentrează pe construirea de pagini web întregi, React.js se concentrează pe construirea de componente reutilizabile. Această abordare modulară face ca dezvoltarea să fie mai ușoară și mai eficientă, deoarece dezvoltatorii pot construi și testa componente independent, apoi le pot folosi în diferite aplicații web fără a fi nevoie să le rescrie. De asemenea, React.js utilizează Virtual DOM pentru a gestiona actualizările paginii, ceea ce face ca aplicațiile să fie mai rapide și mai eficiente decât cele construite folosind alte framework-uri.
npx create-react-app my-app
cd my-app
npm start
În React.js, componentele sunt blocuri de construcție fundamentale ale interfeței utilizatorului. Acestea sunt reutilizabile și pot fi combinate pentru a crea interfețe complexe. Există două tipuri de componente în React.js:
Exemplu de componentă funcțională:
function HelloWorld() { return <h1>Hello, World!</h1>; }
Exemplu de componentă bazată pe clasă: :
class HelloWorld extends React.Component { render() { return <h1>Hello, World!</h1>; } }
Comunicarea între componente este importantă pentru a construi aplicații complexe. În React.js, comunicarea între componente poate fi realizată prin transmiterea de proprietăți de la o componentă părinte la o componentă copil sau prin utilizarea unei funcții callback pentru transmiterea datelor dinspre copil spre părinte.
Componentele pot transmite date către componente copil prin intermediul proprietăților, iar acestea pot fi modificate în funcție de nevoile componente copil. Astfel, orice modificare a proprietăților din componenta părinte va fi reflectată automat în componenta copil.
Iată un exemplu de utilizare a acestui mod de comunicare:
import React from 'react'; function Parinte() { const data = { nume: 'Ion', prenume: 'Popescu' }; return ( <div> <h1>Bun venit, {data.nume} {data.prenume}!</h1> <Copil data={data} /> </div> ); } function Copil(props) { const { nume, prenume } = props.data; return ( <div> <p>Nume: {nume}</p> <p>Prenume: {prenume}</p> </div> ); }
Pentru a comunica dintr-o componentă copil către o componentă părinte în React.js, se poate folosi o funcție callback. Această metodă constă în definirea unei funcții în componenta părinte, pe care o transmitem apoi către componenta copil ca proprietate. Componenta copil poate apela funcția atunci când are nevoie să transmită informații înapoi către componenta părinte.
Iată un exemplu de utilizare a acestei metode:
import React, { useState } from 'react'; function Parinte() { const [mesaj, setMesaj] = useState(''); // Definim o funcție care primește un mesaj // și îl setează ca stare în componenta părinte const handleMesajSchimbat = (noulMesaj) => { setMesaj(noulMesaj); } return ( <div> <p>Mesajul primit: {mesaj}</p> <Copil onMesajSchimbat={handleMesajSchimbat} /> </div> ); } function Copil(props) { const [mesaj, setMesaj] = useState(''); // Funcție care apelează funcția de la părinte pentru a trimite mesajul // din copil înapoi către părinte const handleClick = () => { props.onMesajSchimbat(mesaj); } return ( <div> <input type="text" value={mesaj} onChange={(event) => setMesaj(event.target.value)} /> <button onClick={handleClick}>Trimite mesaj</button> </div> ); }
Această metodă este utilă în situații în care componentele copil trebuie să transmită date către componentele părinte.
Auth0 este o platforma de gestionare a conturilor de utilizatori care ofera suport pentru autentificare si autorizare.
Avantajul in utilizarea unui 3rd party pentru gestionarea conturilor, autentificare si autorizare este ca puteti sa faceti foarte usor outsourcing la responsabilitatile ce tin de securitatea conturilor. Deoarece securitatea este foarte importanta, este foarte usor sa gresiti, mai ales la inceput de drum. Si greselile, de obicei, implica litigii pe sume foarte mari de bani. Este de preferat sa folositi un tert pentru a evita orice potentiale probleme.
Auth0 ofera suport pentru majoritatea tehnologiilor si are un sistem de configurare usor adaptabil.
Pentru a lucra cu Auth0, trebuie sa va creati un cont. Este gratuit. Puteti sa va creati un cont de la 0 sau sa folositi conturi deja existente de Google, Microsoft sau GitHub.
Aplicatiile reprezinta clienti care se vor conecta la sistemul Auth0 pentru operatii de autentificare si autorizare. Din cadrul aplicatiilor veti putea efectua operatii precum login, register, logout in Auth0. Mai mult, aplicatiile vor primi 2 tokeni de la Auth0 inapoi, pentru a valida faptul ca autentificarea s-a realizat cu succes.
Unul dintre acesti 2 tokeni reprezinta un ID Token, si are informatie embedded despre utilizator. Celalalt token reprezinta un Access Token si va fi folosit in comunicarea cu API-uri, in procesul de autorizare.
In functie de tehnologia pe care o folositi, Auth0 va ofera un ghid.
Chiar daca nu lucram inca la backend, este necesar sa inregistram API-ul pe care il vom dezvolta in cadrul Auth0, pentru a putea realiza setarile pentru roluri si permisiuni. Setarile acestui API vor fi folosite de noi, atunci cand vom dezvolta backendul, pentru a putea autoriza cererile care vin de la client (frontend) cu Access Token-ul primit de la Auth0.
Inregistrarea unui API este si ea foarte simpla.
Pentru a putea folosi permisiunile in cadrul API-urilor pe care le vom crea, este necesar sa activam doua optiuni care permit injectarea permisiunilor in Access Token.
Dupa ce ati facut acest lucru, trebuie sa adaugam o serie de permisiuni. Pentru cazul nostru, ne intereseaza sa filtram utilizatorii dupa capabilitati de admin. Asadar, avem nevoie doar de o permisiune, si anume, cea de administrator.
Adaugarea unei permisiuni este si ea, foarte simpla:
Dupa ce avem permisiunile de accesare a API-ului create, putem sa le asignam unor roluri de utilizatori. Nu este obligatoriu sa facem asta, insa rolurile ajuta pentru agregarea mai multor permisiuni sub aceeasi umbrela.
In primul rand, trebuie sa cream un rol:
Dupa ce avem rolul creat, trebuie sa ii asignam permisiunile. Dati click pe rol, si apoi asignati-i permisiunea creata anterior:
Asa cum am spus anterior, frontendul trebuie sa stie cine este admin si cine nu, pentru a putea afisa diferit informatiile. De asemenea, nu este indicat ca frontendul sa acceseze Access Token-ul, deoarece acela este destinat pentru backend.
Pentru a putea adauga informatii in ID Token, Auth0 ofera Actions. Actions reprezinta niste middlewares care sunt injectate in procesele de autentificare si autorizare si sunt complet customizabile.
Pentru a injecta rolul in ID Token, este necesar sa adaugam un middleware in procesul de login:
Felicitari! Daca ati ajuns aici, inseamna ca aveti sistemul pregatit pentru operatiile de autentificare si autorizare. Ultimul pas este acela de a asigna roluri utilizatorilor. In cadrul proiectului nostru, a librariei online, avem nevoie de un administrator.
Asadar, va trebui creat un cont in platforma, folosind functionalitatea oferita de Auth0, integrata in frontendul nostru si apoi, din dashboardul Auth0, va trebui sa ii asignam acestui cont, rolul creat anterior.
Asa cum am prezentat anterior, auth0 are un tutorial foarte bun si usor de parcurs pentru integrarea cu frontendul nostru. In continuare, aveti cateva puncte care, mai mult sau mai putin, sunt prezentate si in tutorial:
Instalarea pachetului respectiv pentru React in proiectul nostru de React
npm install @auth0/auth0-react
Completarea unui fisier de configurare in care vom tine datele statice
const authSettings = { rolesKey: "******************", domain: '********************', clientId: "**********************", audience: "********************" }; export { authSettings };
Configurarea componentei de tip provider, practic un wrapper peste aplicatia noastra
import React from "react"; import React from "react"; import ReactDOM from "react-dom"; import "./index.css"; import App from "./App"; import reportWebVitals from "./reportWebVitals"; import { Auth0Provider } from "@auth0/auth0-react"; import { authSettings } from "./AuthSettings"; ReactDOM.render( <React.StrictMode> <Auth0Provider domain={authSettings.domain} clientId={authSettings.clientId} redirectUri={window.location.origin} > <App /> </Auth0Provider> </React.StrictMode>, document.getElementById("root") );
Redirectarea catre login daca utilizatorul nu este autentificat in componenta noastra de Routing
import React, { useEffect } from "react"; import { BrowserRouter, Route, Routes } from "react-router-dom"; import Analytics from "../pages/Admin/Analytics"; import Book from "../pages/Admin/Book"; import UserBooks from "../pages/User/Books"; import Books from "../pages/Admin/Books"; import Account from "../pages/User/Account"; import { useAuth0 } from "@auth0/auth0-react"; const Router = () => { const { isAuthenticated, loginWithRedirect } = useAuth0(); useEffect(() => { if (!isAuthenticated) { loginWithRedirect(); } }, [isAuthenticated, loginWithRedirect]); return ( isAuthenticated && ( <BrowserRouter> <Routes> <Route exact path="/" element={<UserBooks />} /> <Route exact path="/profile" element={<Account />} /> <Route exact path="books" element={<Books />} /> <Route exact path="books/:id" element={<Book />} /> <Route exact path="analytics" element={<Analytics />} /> </Routes> </BrowserRouter> ) ); }; export default Router;
Adaugarea actiunii de Logout pe butoane
onClick={() => { logout({ returnTo: window.location.origin }); }}
Protejarea rutelor in functie de tipul de utilizator (admin/utilizator normal). De exemplu, ca si utilizator autentificat nu am niciun rol asignat (admin) inseamna ca nu voi avea dreptul sa vad paginile dedicate admin-ului, deci il voi redirectiona catre pagina lui principala in care vede cartile pe care le poate imprumuta.
useEffect(() => { if (user && user[authSettings.rolesKey].length === 0) { navigate("/"); } }, [user]);
Dupa ce ati integrat frontendul cu Auth0, testarea este foarte simpla:
O sa vedeti 2 tokeni, Access Token si Id Token.
Pe JWT.io puteti investiga continutul tokenilor.
ID Tokenul ar trebui sa contina informatii de profil si rolul injectat la pasul 7 (daca este token pentru admin):
Access Tokenul ar trebui sa contina informatii legate de audienta pentru care poate fi folosit si permisiuni injectate la pasul 5, prin optiunea de RBAC: