Table Des Matières
Présentation Rapide
React Router 4 est un ensemble de composants de navigation qui offrent un routage déclaratif dans vos applications React. Dans ce tutoriel, vous allez apprendre à utiliser React Router 4 à l’aide d’exemples pratiques.
Le routage est de la plus haute importance dans presque toutes les architectures d’application. Plus votre application est grande, plus votre fonctionnalité de routage devient complexe, des scénarios de routage simples à ceux profondément imbriqués.
React Router est la bibliothèque la plus populaire et la plus utilisée pour le routage dans les applications React. Au fur et à mesure que votre application nécessite plusieurs vues et itinéraires, il est idéal de choisir un bon routeur pour gérer la transition entre les vues, les redirections, obtenir facilement les paramètres d’URL, etc.
Jusqu’à présent, les versions précédentes de React Router impliquaient la déclaration préalable des routes de votre application, déclarant toutes les routes dans un fichier dans le cadre de l’initialisation de votre application avant le rendu. Avec React Router 4, vous arrivez à l’itinéraire de manière déclarative. L’API de React Router 4 est essentiellement composée de composants, ce qui la rend facile à utiliser si vous composez déjà des composants dans React. Plongeons dedans!
Installation et Configuration
Vous aurez besoin de:
- Node.js (version 6.0 ou supérieure) et npm.
- create-react-app pour amorcer un nouveau projet.
React Router est composé de ces paquets: react-router, react-router-dom, et react-router-native:
- React-router: comprend les composants de routage de base.
- React-router-dom: comprend l’API de routage requise pour les navigateurs.
- React-router-native: comprend les API de routage pour les applications mobiles.
Créez un nouveau projet avec create_react_app et accédez au répertoire créé comme indiqué ci-dessous:
create-react-app bose cd bose
Installez react-router-dom.
npm install --save react-router-dom
Ce Que Nous Allons Couvrir
Nous allons nous concentrer sur l’utilisation de React Router 4 pour le navigateur. Nous couvrirons les concepts très importants énumérés ci-dessous:
- Routage de base
- Routage imbriqué et paramètres d’URL
- Protection de route et authentification
- Personnalisation des composants de lien
- Manipulation de routes inexistantes
- Rendre la barre latérale
Routage de base
Il existe deux types de composants de routeur que vous pouvez utiliser dans votre application Web React. BrowserRouter et HashRouter. Le premier vous donne une URL sans #, tandis que le dernier vous donne une URL avec le #
Notez que Si vous créez une application Web prenant en charge les navigateurs existants, il est recommandé d’utiliser HashRouter.
Ouvrez votre src / index.js et ajoutez le code ci-dessous:
import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import './index.css'; import App from './App'; import registerServiceWorker from './registerServiceWorker'; ReactDOM.render( <Router> <App /> </Router>, document.getElementById('root')); registerServiceWorker();
Dans le code ci-dessus, j’ai importé le composant BrowserRouter, Route et Link depuis react-router-dom. Et j’ai enveloppé le composant <App/> avec Router qui est l’alias de BrowserRouter. Le composant routeur est la première étape du routage réussi. Il sert de conteneur pour tous les autres composants de route. De plus, le composant routeur ne peut avoir qu’un seul élément ou composant enfant. Maintenant, comment définissons-nous nos itinéraires?
Ouvrez src / App.js. Ici, nous allons définir nos itinéraires.
import React, { Component } from 'react'; import { Route, Link } from 'react-router-dom'; import './App.css'; const Home = () => ( <div> <h2> Home </h2> </div> ); const Airport = () => ( <div> <ul> <li>Jomo Kenyatta</li> <li>Tambo</li> <li>Med Mùs</li> </ul> </div> ); const City = () => ( <div> <ul> <li>San Francisco</li> <li>Istanbul</li> <li>Tokyo</li> </ul> </div> ); class App extends Component { render() { return ( <div> <ul> <li><Link to="/">Home</Link></li> <li><Link to="/airports">Airports</Link></li> <li><Link to="/cities">Cities</Link></li> </ul> <Route path="/" component={Home}/> <Route path="/airports" component={Airport}/> <Route path="/cities" component={City}/> </div> ); } } export default App;
Dans le code ci-dessus, nous avons des liens qui devraient diriger l’utilisateur vers /, / airports, et les villes cities en utilisant le composant <Link> . Chacun de ces liens a un composant qui devrait être rendu une fois que l’emplacement actuel correspond au chemin de l’itinéraire. Cependant, il y a quelque chose qui ne va pas bien ici. Vérifions les résultats.
Route des aéroports
Home qui est l’interface utilisateur du composant Acceuil devrait être rendu seulement sur / , route racine. Cependant, il est rendu sur toutes les routes. / correspond aux routes des /cities villes et des /airports aereports, rendant ainsi son composant dans ces deux autres routes. La solution à ceci est d’ajouter simplement le prop exact à la / route.
src/App.js
<Route path="/" exact component={Home}/> <Route path="/airports" component={Airport}/> <Route path="/cities" component={City}/>
La route des aéroports sans rendre l’interface utilisateur du composant Home
Dans les exemples ci-dessus, tous les composants <Route /> ont un composant prop qui rend un composant lorsque l’URL visitée correspond au chemin de la Route. Que faire si vous voulez rendre juste une petite fonction au lieu d’un composant entier? Eh bien dans ce cas vous pouvez utiliser le prop render comme indiqué dans le code ci-dessous.
<Route path="/airports"
render={() => (<div> This is the airport route </div>)}/>
Paramètres de routage et d’URL imbriqués
Que faire si vous voulez un lien comme celui là: /courses/business, et / cours / technologie /? Comment voulez-vous accomplir cela?
src/App.js
import React, { Component } from 'react'; import { Route, Link } from 'react-router-dom'; import './App.css'; const Courses = ({ match }) => ( <div> <ul> <li><Link to="/courses/technology">Technology</Link></li> <li><Link to="/courses/business">Business</Link></li> <li><Link to="/courses/economics">Economics</Link></li> </ul> <Route exact path="/courses/technology" render={() => (<div> This is technology </div>)}/> <Route path="/courses/business" component={() => (<div> This is business </div>)}/> <Route path="/courses/economics" component={() => (<div> This is economics </div>)}/> </div> ); /* Home Component */ // code hidden /* City Component */ //code hidden class App extends Component { render() { return ( <div> <ul> <li><Link to="/">Home</Link></li> <li><Link to="/courses">Courses</Link></li> <li><Link to="/cities">Cities</Link></li> </ul> <Route path="/" exact component={Home}/> <Route path="/courses" component={Courses}/> <Route path="/cities" component={City}/> </div> ); } } export default App;
Si l’emplacement de l’URL correspond au chemin / courses, les liens technologiques, commerciaux et économiques sont rendus via le composant Courses. Pour aller plus loin, si l’emplacement de l’URL correspond aux chemins /courses/technology, /courses/business, et /courses/economics, alors This is technology, This is business, et This is economics sont rendus respectivement.
En tant que développeur, je suis sûr que vous regardez déjà cette approche avec un ensemble d’yeux de refactoring 🙂 . Dans l’exemple de code ci-dessus, il y a beaucoup de répétitions et de hardcoding. Plus il y a de lignes de code, plus il devient difficile de changer de route. Réfléchissons.
React Router 4 est livré avec une API de correspondance match. L’objet de correspondance est créé lorsque le chemin d’accès et l’emplacement de l’URL d’un routeur correspondent bien. L’objet de correspondance a quelques propriétés, mais je vais décrire les propriétés dont vous devez immédiatement avoir connaissance:
- match.url: renvoie une chaîne qui montre l’emplacement de l’URL. Utilisé pour s
- match.path: renvoie une chaîne qui indique le chemin de l’itinéraire. Utilisé aussi pour s
- match.params: renvoie un objet avec des valeurs analysées à partir de l’URL.
Refactorisons étape par étape. Refactorisez le composant Courses pour que l’objet de correspondance match ressemble à ceci:
const Courses = ({ match }) => ( <div> <ul> <li><Link to={`${match.url}/technology`}>Technology</Link></li> <li><Link to={`${match.url}/business`}>Business</Link></li> <li><Link to={`${match.url}/economics`}>Economics</Link></li> </ul> <Route exact path="/courses/technology" render={() => (<div> This is technology </div>)}/> <Route path="/courses/business" component={() => (<div> This is business </div>)}/> <Route path="/courses/economics" component={() => (<div> This is economics </div>)}/> </div> );
Testez si vos URL fonctionnent. Faites de même pour les routes mais avec match.path.
const Courses = ({ match }) => ( <div> <ul> <li><Link to={`${match.url}/technology`}>Technology</Link></li> <li><Link to={`${match.url}/business`}>Business</Link></li> <li><Link to={`${match.url}/economics`}>Economics</Link></li> </ul> <Route exact path={`${match.path}/technology`} render={() => (<div> This is technology </div>)}/> <Route path={`${match.path}/business`} component={() => (<div> This is business </div>)}/> <Route path={`${match.path}/economics`} component={() => (<div> This is economics </div>)}/> </div> );
Vérifiez votre application Tout devrait bien fonctionner. Maintenant, une dernière étape. Nous pouvons réellement remplacer ces trois lignes de code <Route> par une seule ligne.
const Courses = ({ match }) => ( <div> <ul> <li><Link to={`${match.url}/technology`}>Technology</Link></li> <li><Link to={`${match.url}/business`}>Business</Link></li> <li><Link to={`${match.url}/economics`}>Economics</Link></li> </ul> <Route exact path={`${match.path}/:course`} render={({match}) => (<div> This is {match.params.course} </div>)}/> </div> );
Nous avons utilisé le match.params qui fournit un objet clé / valeur de l’emplacement de l’URL. :course c’est l’URL param. Par conséquent, match.params.course fournira la valeur de l’emplacement correct de l’URL. Impressionnant! 🙂
Protection de route et authentification
Lors du développement d’applications Web, il existe des scénarios dans lesquels certaines routes doivent être protégées contre l’accès. La plupart du temps, ces itinéraires ne sont accessibles qu’aux utilisateurs autorisés.
Dans les versions précédentes de React Router telles que la v3 (3ème version), le code de protection de l’itinéraire ressemble à ceci:
index.js
const Root = () => { return ( <div className="container"> <Router history={browserHistory}> <Route path="/" component={Display}/> <Route path="/upload" component={Upload} onEnter={requireAuth} /> <Route path="/callback" component={Callback} /> </Router> </div> ) }
Le composant <Route /> avait un prop (accessoire) onEnter qui accepte une méthode qui permet l’entrée ou le refus d’un emplacement d’URL en fonction de l’état d’authentification de l’utilisateur. Maintenant, c’est différent pour React Router 4.
Construisons trois composants, Public, Private, et Login.
App.js
import React, { Component } from 'react'; import { Route, Link, BrowserRouter as Router, } from 'react-router-dom'; const Public = () => ( <div> This is a public page </div> ); const Private = () => ( <div> This is a private page </div> ); const Login = () => ( <div> Login Page <button>login</button> </div> ); class App extends Component { render() { return ( <Router> <div style={{width: 1000, margin: '0 auto'}}> <ul> <li><Link to='/public'> Public </Link></li> <li><Link to='/private'> Private </Link></li> </ul> <hr/> <Route path='/public' component={Public} /> <Route path='/private' component={Private} /> </div> </Router> ); } } export default App;
En ce moment, nous pouvons accéder aux deux routes, /public, et /private. Maintenant, faisons en sorte que la route / private (privée) ne soit pas accessible jusqu’à ce qu’un utilisateur soit connecté. React Router 4 utilise une approche déclarative, donc c’est pratique que nous ayons un composant tel que <SecretRoute /> que nous pouvons utiliser. Cependant, la bibliothèque de routeur de réaction 4 ne le fournit pas. Nous allons le construire. Mais nous allons recourir à un service d’authentification AuthService.
Dans cet exemple, le service d’authentification sera simplement un objet comme ça:
const AuthService = { isAuthenticated: false, authenticate(cb) { this.isAuthenticated = true setTimeout(cb, 100) }, logout(cb) { this.isAuthenticated = false setTimeout(cb, 100) }
Maintenant, construisons le <SecretRoute /> comme ça:
const SecretRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={(props) => ( AuthService.isAuthenticated === true ? <Component {...props} /> : <Redirect to='/login' /> )} /> );
Le composant SecretRoute
Le code ci-dessus illustre simplement que si le statut d’authentification de l’utilisateur est vrai, alors un composant serait rendu sinon l’utilisateur serait redirigé vers la route / login. Essayons.
App.js
import React, { Component } from 'react'; import { Route, Link, Redirect, BrowserRouter as Router, } from 'react-router-dom'; const Login = () => ( <div> Login Page <button>login</button> </div> ); const AuthService = { isAuthenticated: false, authenticate(cb) { this.isAuthenticated = true setTimeout(cb, 100) }, logout(cb) { this.isAuthenticated = false setTimeout(cb, 100) } }; const SecretRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={(props) => ( AuthService.isAuthenticated === true ? <Component {...props} /> : <Redirect to='/login' /> )} /> ); class App extends Component { render() { return ( <Router> <div style={{width: 1000, margin: '0 auto'}}> <ul> <li><Link to='/public'> Public </Link></li> <li><Link to='/private'> Private </Link></li> </ul> <hr/> <Route path='/public' component={Public} /> <SecretRoute path='/private' component={Private} /> </div> </Router> ); } } export default App;
Lorsque vous cliquez sur le lien Privé private, vous êtes redirigé vers / login route. Génial! Allons-y faisant un pas de plus en essayant de nous connecter et de nous déconnecter. Modifiez le composant de connexion comme ceci:
App.js
... class Login extends React.Component { state = { redirectToPreviousRoute: false }; login = () => { AuthService.authenticate(() => { this.setState({ redirectToPreviousRoute: true }); }); }; render() { const { from } = this.props.location.state || { from: { pathname: "/" } }; const { redirectToPreviousRoute } = this.state; if (redirectToPreviousRoute) { return <Redirect to={from} />; } return ( <div> <p>You must log in to view the page at {from.pathname}</p> <button onClick={this.login}>Log in</button> </div> ); } }
Nous avons modifié le composant de connexion pour pouvoir avoir une fonction de connexion login et rediriger également vers l’itinéraire que l’utilisateur essayait de se connecter lorsque l’utilisateur s’est vu refuser l’accès. Cela devrait être le comportement typique de votre système de routage, sinon les utilisateurs seront toujours redirigés vers une page particulière plutôt que d’où ils viennent!
Maintenant, nous allons devoir modifier les props du composant <Redirect /> dans <SecretRoute />.
App.js
const SecretRoute = ({ component: Component, ...rest }) => ( <Route {...rest} render={(props) => ( AuthService.isAuthenticated === true ? <Component {...props} /> : <Redirect to={{ pathname: '/login', state: { from: props.location } }} /> )} /> );
Nous avons presque fini. Cependant, ne serait-il pas bien si nous pouvons fournir un bouton de déconnexion pour l’utilisateur après une authentification réussie? Créons un composant <AuthStatus />.
App.js
... const AuthStatus = withRouter(({ history }) => ( AuthService.isAuthenticated ? ( <p> Welcome! <button onClick={() => { AuthService.logout(() => history.push('/')) }}>Sign out</button> </p> ) : ( <p>You are not logged in.</p> ) ));
Dans l’exemple de code ci-dessus, nous avons utilisé withRouter et history.push. withRouter est un composant d’ordre supérieur de React Router qui permet le rendu de son composant chaque fois que l’itinéraire change avec les mêmes props. history.push est un moyen de rediriger les utilisateurs en utilisant le composant <Redirect /> depuis React Router.
Maintenant, allez-y et rendez le composant <AuthStatus />
App.js
class App extends Component { render() { return ( <Router> <div style={{width: 1000, margin: '0 auto'}}> <AuthStatus /> <ul> <li><Link to='/public'> Public </Link></li> <li><Link to='/private'> Private </Link></li> </ul> <hr/> <Route path='/public' component={Public} /> <Route path="/login" component={Login}/> <SecretRoute path='/private' component={Private} /> </div> </Router> ); } }
Maintenant, essayez à nouveau dans le navigateur. Vous devriez pouvoir vous connecter et vous déconnecter avec succès!
Personnalisation Du Composant Lien
Personnalisation du composant lien? Qu’est-ce que c’est? C’est simple. Vous apprendrez à personnaliser vos liens pour avoir un aspect distinctif lorsqu’un lien particulier est actif. React Router 4 a un moyen facile d’accomplir cette tâche.
Ayez le code ci-dessous dans votre App.js comme ceci:
import React from 'react' import { BrowserRouter as Router, Route, Link } from 'react-router-dom' const Home = () => ( <div> <h2>Home Page</h2> </div> ) const Contact = () => ( <div> <h2>Contact Page</h2> </div> ) class App extends React.Component { render() { return ( <Router> <div> <CustomLink exact={true} to="/"> Home </CustomLink> <CustomLink to="/contact"> Contact </CustomLink> <hr/> <Route exact path="/" component={Home}/> <Route path="/contact" component={Contact}/> </div> </Router> ) } } export default App;
Le <CustomLink /> est chargé de rendre le lien actif distinct. Maintenant, qu’est-ce qui fait le composant <CustomLink />? Découvrez le code ci-dessous:
const CustomLink = ({ children, to, exact }) => ( <Route path={to} exact={exact} children={({ match }) => ( <div className={match ? 'active' : ''}> {match ? '> ' : ''} <Link to={to}> {children} </Link> </div> )}/> );
Ce n’est pas complexe. Le <CustomLink> a exploité la puissance de <Route>. Dans le code ci-dessus, il utilise l’objet match pour déterminer s’il doit ajouter un symbole lorsque le chemin correspond à l’emplacement de l’URL.
Il y a 3 façons de rendre quelque chose avec un <Route>; <Route component> Composant route, <Route render> Rendu route, et <Route children> Route enfant. Le code ci-dessus utilise le prop enfants. Ce rendu prend en charge une fonction qui reçoit tous les mêmes paramètres d’acheminement que les méthodes de rendu et de composant, sauf lorsqu’une route ne correspond pas à l’emplacement de l’URL. Ce processus vous donne le pouvoir d’ajuster dynamiquement votre interface utilisateur selon que l’itinéraire correspond ou non. Et c’est tout ce dont nous avons besoin pour créer un lien personnalisé!
Manipulation Des Routes Inexistantes
En tant que développeur, vous devez gérer des scénarios dans lesquels certaines routes n’existent pas. Si un utilisateur tombe sur votre site et visite un itinéraire inexistant tel que / babalawo. Que faire? Est-ce que vous laissez juste votre site se casser?
Voici comment gérer ce scénario. Ajoutez du code à votre App.js comme ceci:
App.js
import React, { Component } from 'react'; import { Route, Link, Redirect, Switch, BrowserRouter as Router, } from 'react-router-dom'; const Home = () => ( <div> <h2>Home Page</h2> </div> ) const Contact = () => ( <div> <h2>Contact Page</h2> </div> ) class App extends Component { render() { return ( <Router> <div> <ul> <li> <Link to="/">Home</Link> </li> <li> <Link to="/contact">Contact</Link> </li> </ul> <Switch> <Route exact path="/" component={Home}/> <Route path="/contact" component={Contact}/> <Route render={() => (<div> Sorry, this page does not exist. </div>)} /> </Switch> </div> </Router> ); } } export default App;
Dans le code ci-dessus, nous avons importé un nouveau composant, <Switch /> depuis React Router. Et nous avons enveloppé nos routes dans le composant <Switch />. Maintenant, si aucune des URL visitées ne correspond aux routes définies avec un chemin, alors le composant <Switch /> appelle <Route /> sans chemin ni fonction de rendu.
Essayez-le dans votre navigateur. Visitez une URL qui n’existe pas. Votre application affichera un message Sorry, this page does not exist (Désolé, cette page n’existe pas).
Rendu SideBar (Barre Latérale)
La barre latérale (Sidebars) dans les applications existent depuis très longtemps. Apprenons comment faire une barre latérale en utilisant React Router 4. La première étape consiste à lancer nos routes dans un tableau comme ceci:
import React from 'react' import { BrowserRouter as Router, Route, Link, } from 'react-router-dom' const routes = [ { path: '/', exact: true, leftbar: () => <div>Home</div>, main: () => <h2>Home</h2> }, { path: '/about', leftbar: () => <div>About</div>, main: () => <h2>About</h2> }, { path: '/contact', leftbar: () => <div>Contact</div>, main: () => <h2>Contact</h2> } ] class App extends React.Component { render() { return ( <Router> <div style={{ display: 'flex' }}> <div style={{ padding: '10px', width: '40%', background: '#FF6347' }}> <ul style={{ listStyleType: 'none', padding: 0 }}> <li><Link to="/">Home</Link></li> <li><Link to="/about">About</Link></li> <li><Link to="/contact">Contact</Link></li> </ul> </div> </div> </Router> ) } } export default App
Dans le code ci-dessus, nous avons leftbar une barre gauche et une clé main principale. Ils seront bientôt utiles et rendront notre travail super facile.
Maintenant, tout ce que nous devons faire est de mapper sur le tableau routes comme indiqué dans le code ci-dessous:
App.js
render() { return ( <Router> <div style={{ display: 'flex' }}> <div style={{ padding: '10px', width: '40%', background: '#FF6347' }}> <ul style={{ listStyleType: 'none' }}> <li><Link to="/">Home</Link></li> <li><Link to="/about">About</Link></li> <li><Link to="/contact">Contact</Link></li> </ul> {routes.map((route) => ( <Route key={route.path} path={route.path} exact={route.exact} component={route.leftbar} /> ))} </div> <div style={{ flex: 1, padding: '20px' }}> {routes.map((route) => ( <Route key={route.path} path={route.path} exact={route.exact} component={route.main} /> ))} </div> </div> </Router> ) }
Dans le code ci-dessus, chaque fois que le chemin de l’itinéraire correspond à l’emplacement de l’URL, le composant leftbar (La barre latérale gauche) sera rendu. Essayez-le dans votre navigateur et voir votre barre latérale gauche en action!
Authentifier Vos Applications React Avec Auth0
Nous pouvons protéger nos applications et API afin que seuls les utilisateurs authentifiés puissent y accéder. Explorons comment faire avec une application React utilisant Auth0.
Nous aurons besoin d’un compte Auth0 pour gérer l’authentification. Pour vous inscrire à un compte gratuit, nous pouvons suivre ce lien. Ensuite, configurons une application client et une API Auth0 afin que Auth0 puisse s’interfacer avec une application React.
Configuration d’une application client
- Allons à notre tableau de bord Auth0 et cliquons sur le bouton “create a new client” (créer un nouveau client).
- Appelons notre application comme “React Demo” et sélectionnez “Single Page Web Applications” (Applications Web Page unique).
- Dans les paramètres de notre nouvelle application client Auth0, ajoutons http://localhost:3000/callback aux URLs de rappel autorisés.
- Si vous le souhaitez, nous pouvons mettre en place des liens sociaux. Nous pouvons ensuite les activer pour notre application dans les options Client sous l’onglet Connexions. L’exemple montré dans la capture d’écran ci-dessus utilise la base de données de nom d’utilisateur / mot de passe, Facebook, Google et Twitter. Pour la production, assurez-vous de configurer les bonnes clés sociales et ne laissez pas les connexions sociales définies pour utiliser les clés de développement Auth0.
Configurer une API
- Accédez aux API de votre tableau de bord Auth0 et cliquez sur le bouton “Créer une API”. Entrez un nom pour l’API. Définissez l’identifiant sur l’URL de votre point de terminaison API. Dans cet exemple, il s’agit de http: //localhost:3001 /api/. L’algorithme de signature doit être RS256.
- Vous pouvez consulter l’exemple Node.js sous l’onglet Démarrage rapide dans les paramètres de votre nouvelle API. Nous allons implémenter notre API Node de cette manière, en utilisant Express, express-jwt et jwks-rsa.
Nous sommes maintenant prêts à implémenter l’authentification Auth0 à la fois sur nos API client backend et node.
Dépendances et configuration
Il y a seulement deux dépendances que nous devons vraiment installer: auth0.js et history. Pour ce faire, émettons npm install –save auth0-js history dans la racine du projet.
Note: Comme nous voulons la meilleure sécurité disponible, nous allons compter sur la page de connexion Auth0. Cette méthode consiste à rediriger les utilisateurs vers une page de connexion hébergée par Auth0, facilement personnalisable depuis le tableau de bord.
Après l’avoir installé, nous pouvons créer un service d’authentification pour l’interface avec le script auth0.js. Appelons ce service Auth et créons le dans le répertoire src / Auth / avec le code suivant:
import history from '../history'; import auth0 from 'auth0-js'; export default class Auth { auth0 = new auth0.WebAuth({ // the following three lines MUST be updated domain: 'bkrebs.auth0.com', audience: 'https://bkrebs.auth0.com/userinfo', clientID: '3co4Cdt3h3x8En7Cj0s7Zg5FxhKOjeeK', redirectUri: 'http://localhost:3000/callback', responseType: 'token', scope: 'openid' }); constructor() { this.login = this.login.bind(this); this.logout = this.logout.bind(this); this.handleAuthentication = this.handleAuthentication.bind(this); this.isAuthenticated = this.isAuthenticated.bind(this); } handleAuthentication() { this.auth0.parseHash((err, authResult) => { if (authResult && authResult.accessToken) { this.setSession(authResult); history.replace('/home'); } else if (err) { history.replace('/home'); console.log(err); } }); } setSession(authResult) { // Set the time that the access token will expire at let expiresAt = JSON.stringify((authResult.expiresIn * 1000) + new Date().getTime()); localStorage.setItem('access_token', authResult.accessToken); localStorage.setItem('expires_at', expiresAt); // navigate to the home route history.replace('/home'); } login() { this.auth0.authorize(); } logout() { // Clear access token and expiration from local storage localStorage.removeItem('access_token'); localStorage.removeItem('expires_at'); // navigate to the home route history.replace('/home'); } isAuthenticated() { // Check whether the current time is past the // access token's expiry time let expiresAt = JSON.parse(localStorage.getItem('expires_at')); return new Date().getTime() < expiresAt; } }
Le service Auth que vous venez de créer contient des fonctions permettant de gérer les différentes étapes du processus de connexion / inscription. La liste suivante résume brièvement ces fonctions et leurs descriptions:
- handleAuthentication: cherche le résultat de l’authentification dans le hash d’URL. Ensuite, traite le résultat avec la méthode parseHash de auth0-js;
- setSession: définit le jeton (token) d’accès de l’utilisateur et l’heure d’expiration de ce jeton d’accès;
- login: initie le processus de connexion, en redirigeant les utilisateurs vers la page de connexion;
- logout: supprime les jetons de l’utilisateur et le délai d’expiration du stockage du navigateur;
- isAuthenticated: vérifie si l’heure d’expiration du jeton d’accès de l’utilisateur a passé;
Outre ces fonctions, la classe contient un champ appelé auth0 qui est initialisé avec des valeurs extraites du client Auth0. Gardons à l’esprit que nous devons les mettre à jour en conséquence avant de continuer.
Les lecteurs attentifs ont probablement remarqué que le service Auth importe également un module appelé history dont nous n’avons pas parlé. Nous pouvons définir ce module en seulement deux lignes, mais définissons-le dans un fichier pour fournir la réutilisabilité. Appelons ce fichier ./src/history/history.js et ajoutons le code suivant:
import createHistory from 'history/createBrowserHistory' export default createHistory()
Après avoir créé les deux éléments, nous pouvons refactoriser notre composant App pour utiliser le service Auth.
import React, { Component } from 'react'; import { Navbar, Button } from 'react-bootstrap'; import './App.css'; class App extends Component { goTo(route) { this.props.history.replace(`/${route}`) } login() { this.props.auth.login(); } logout() { this.props.auth.logout(); } render() { const { isAuthenticated } = this.props.auth; // ... render the view } } export default App;
Notez que nous passons ce service à travers props. Par conséquent, lorsque vous incluez le composant App, nous devons y injecter l’authentification: <App auth = {auth} />.
Considérant que nous utilisons la page de connexion Auth0, nos utilisateurs sont retirés de l’application. Cependant, après s’être authentifiés, les utilisateurs reviennent automatiquement à l’URL de rappel que nous avons configurée précédemment (http://localhost:3000/callback). Cela signifie que nous devons créer un composant responsable de cette URL:
import React, { Component } from 'react'; import loading from './loading.svg'; class Callback extends Component { render() { const style = //... return ( <div style={style}> <img src={loading} alt="loading"/> </div> ); } } export default Callback;
Ce composant peut simplement contenir un indicateur de chargement qui continue à tourner pendant que l’application configure une session côté client pour les utilisateurs. Une fois la session configurée, nous pouvons rediriger les utilisateurs vers un autre itinéraire.
Conclusion
Comprendre React Router 4 nécessite un changement dans votre modèle mental de routage. J’ai couvert les principaux concepts d’API pour l’utilisation de React Router 4 pour le web dans ce tutoriel. Dans des prochianes articles notamment relatifs a cette thématique, je vais couvrir d’autre aspecrts concernant react.