Comment configurer l'authentification utilisateur à l'aide de React, Redux et Redux Saga

MISE À JOUR (12.02.2019): J'ai récemment mis à jour ce projet avec les routeurs de réaction les plus récents, c'est-à-dire la version 4.3.1 qui est react-router-dom. Veuillez vous rendre dans son référentiel pour voir les modifications.

Dans mon blog précédent, j'ai écrit comment écrire une architecture évolutive dans Node.js. Depuis que j'ai utilisé postman pour tester le fonctionnement de cette plate-forme, j'ai pensé que ce serait une bonne idée d'avoir son implémentation côté client. Pour écrire son côté client, j'ai décidé d'utiliser la pile technologique ci-dessous:

  • Réagir
  • Redux
  • Redux-Saga
  • Routeur React

Cet article suppose que vous connaissez déjà les concepts de réaction et de base de Redux et Redux-Saga.

Commencer

Clonez mon référentiel de blog précédent. CDdans son dossier racine et exécutez npm install. Cela installera toutes les dépendances.

Deuxièmement, installez mongodbdans votre machine. Une fois installé, exécutez le serveur mongo en utilisant lemongodcommande dans votre terminal, s'il n'est pas démarré en tant que service sur votre machine.

Ensuite, assurez-vous que le package nodemon est installé sur votre machine globalement . Accédez au dossier côté serveur et exécuteznodemon index.jspour exécuter le serveur principal.

Maintenant que notre backend est opérationnel, il est temps d'entrer dans son implémentation côté client.

Si vous ne l'avez pas encore installé create-react-apppuis installez-le en utilisant la commande suivante.

npm install create-react-app -g

Cette commande installera create-react-appglobalement .

Créer le projet

Il est maintenant temps de créer un projet. Utilisation:

create-react-app react-login

Cela créera un nouveau projet avec le nom react-login. Allez-y et cddans ce dossier. Ouvrez votrepackage.jsonfichier dans votre éditeur préféré et ajoutez les dépendances suivantes:

Nous n'avons pas besoin de propriétés supplémentaires dans ce package.jsonfichier. Nous pouvons simplement les supprimer, mais je vais le laisser tel quel et avancer pour que nous arrivions à une partie intéressante de ce blog.

Maintenant, lancez simplement:

npm install

qui installera toutes les dépendances mentionnées ci-dessus.

Fichier d'index

Pour commencer, ouvrez le index.jsfichier et placez le code ci-dessous dans ce fichier.

Dans ce code, nous importons reactet react-dom. Ensuite, nous importons Routeret browserHistorydepuis react-router. Ceux-ci sont nécessaires à des fins de routage, que j'utiliserai plus tard dans leroutes/index.jsfichier. Ensuite, nous importons Provider, cela est utilisé pour fournir un magasin aux composants enfants.

configureStoreet routessont quelque chose que nous allons importer ensuite et que je vais implémenter dans une seconde. Importez-les simplement tels quels et utilisez-les dans ce fichier comme indiqué ci-dessus.

Maintenant, notre fichier d'index est configuré.

Configuration du magasin

Créez un nouveau dossier appelé storeà l'intérieur de srcdossier. Dans ce nouveau dossier, créez un fichier appelé configureStore.js,et collez le code suivant dans ce fichier.

D'abord, nous importons createStore, qui sera utilisé pour createStore, et applyMiddlewarequi sera utilisé pour appliquer des middlewares à notre magasin - des sagas dans ce cas, mais nous y reviendrons plus tard dans ce blog - à partir de redux.

Nous importons ensuite rootReducer- nous allons créer cela plus tard. Pour l'instant, importez-le simplement et utilisez-le tel quel. Ceci est suivi de la fonction configureStore, qui retourne un objet en appelant la createStorefonction et en passant rootReducercomme paramètre.

Enfin, export configureStorerend configureStoredisponible dans le index.jsfichier, construit plus tôt.

Maintenant que c'est hors de notre chemin, allez-y et créez le src/reducersdossier, créez le fichier index.js et collez le code ci-dessous dans ce fichier.

Ce fichier est chargé d'importer le reste des réducteurs dans le dossier des réducteurs, de les combiner et de les exporter afin qu'ils soient disponibles pour être utilisés dans configureStore.js. Nous apporterons des modifications à ce fichier lorsque nous ajouterons de nouveaux réducteurs plus tard dans ce blog.

Fichier de routage

Heure du fichier des routes. Allez-y et créez lesrc/routesdossier et dans ce dossier, créez un index.jsfichier. Maintenant, ouvrez-le et collez le code ci-dessous.

L'objectif principal de ce fichier est de gérer le routage dans notre projet. Le fichier importe React, Routeet IndexRoute. Après cela, nous avons besoin d'un conteneur, dans ce cas, j'importe container/App, que nous allons écrire bientôt. Ensuite RegisterPage, qui est un composant, et nous écrirons cela aussi.

Dans le parent Route, lorsque le chemin d'accès à la maison correspond, nous rendons simplement notre Appconteneur. Les IndexRouteutilisateurs verront RegisterPagece qui sera rendu à l'intérieur du Appconteneur.

Récipient

Il est maintenant temps pour le conteneur. Allez-y et créez un nouveau dossier appelé container. Dans ce dossier, créez un nouveau fichier appelé App.jset placez le code ci-dessous dans ce fichier.

C'est assez simple. L'objectif principal de ce fichier est de rendre le reste des composants.{this.props.children}sert cet objectif.

enregistrement

Il est maintenant temps pour registerPage. Créer un nouveau dossiersrc/componentset créez un composant dans le dossier des composants appeléregisterPage.js. Collez le code ci-dessous dans ce composant.

Pour l'instant, c'est un composant très simple. Nous éditerons cela plus tard pour ajouter un formulaire d'inscription et y mettre des fonctionnalités.

Production

Après avoir créé tous les dossiers et fichiers ci-dessus, exécutez npm startvotre projet et ouvrez//localhost:3000dans votre navigateur. Vous devriez pouvoir voir le résultat ci-dessous.

Cliquer sur connexion ici ne redirigera pas vers la route de connexion que nous corrigerons ensuite.

Faire fonctionner

Routage

Pour que le routage fonctionne, créez d'abord un nouveau composant dans le dossier des composants. Nommez-le loginPage.jset placez le code ci-dessous dans ce composant.

Ce composant est très simple. Il rend le contenu de base et un lien pour enregistrer le composant.

Ouvrez maintenant le routes.jsfichier, que nous avons déjà créé ci-dessus, et apportez les modifications suivantes.

Modifiez l'itinéraire de l'index en LoginPagecar nous souhaitons que les utilisateurs atterrissent sur le composant de connexion lorsqu'ils visitent la page d'accueil. Avant de faire cela, importez-le depuis le dossier des composants.

Maintenant, actualisez votre navigateur et vous devriez pouvoir voir en loginPagepremier. Lorsque vous cliquez sur le lien «Inscrivez-vous ici», registerPagedoit être rendu.

Maintenant, nous avons les routes de base qui fonctionnent.

Connexion et inscription

enregistrement

Afin de faire fonctionner le processus de connexion, je vais d'abord gérer le processus d'enregistrement afin que nous ajoutions des utilisateurs dans notre base de données. Alors allons-y, ouvrons-le components/registerPage.jset mettons-le à jour avec le contenu ci-dessous.

Il semble y avoir beaucoup de code dans ce fichier maintenant, mais tout est simple. Nous importons d'abordconnectpour connecter notre storeavec leregisterPagecomposant. Ensuite, nous importonsregisterUserActionque nous écrirons ensuite.

Dans la renderfonction, je vérifie d'abord la réponse du serveur si elle existe, puis j'attribue les propriétés de réussite et de message reçues du serveur. Cela peut être une fonction distincte mais, par souci de simplicité, je les ai placées dans la renderfonction.

Ensuite, il y a un formulaire d'inscription. Lorsque l'utilisateur clique sur le bouton d'enregistrement, il déclenche la onHandleRegistrationfonction qui récupère les données saisies par l'utilisateur à partir du formulaire, etdispatch registerUserActionavec leurs données comme paramètres. Nous allons écrire des actions à l'étape suivante.

Pour que le code ci-dessus fonctionne, nous devons mapStateToProps, comme nous le faisons au bas du composant, le connecter au registerPagecomposant à la fin.

Actions

Il est maintenant temps d'ajouter des actions. Allez-y et créez lesrc/actionsdossier. Créer leindex.jsfichier et placez-y le code ci-dessous.

Ce code exporte certaines constantes que nous utiliserons tout au long de notre projet.

Maintenant, allez-y et créez le authenticationActions.jsfichier dans le même dossier et placez-y le code ci-dessous.

Ici, j'importe le fichier d'index, qui exporte les constantes, puis je export registrationUserActionretourne un objet avec le type d'action et les données utilisateur. Le type d'action dans ce cas est REGISTER_USER. Cette action sera envoyée lorsqu'un utilisateur tente de s'inscrire, et cette action sera disponible tout au long de notre projet que nous écouterons dans nos sagas.

Sagas

Nous sommes maintenant au stade où nous pouvons introduire nos sagas dans notre projet. Si vous êtes nouveau sur Redux-Saga, je vous suggère de parcourir ce blog avant de continuer.

Si vous connaissez déjà les sagas, allez-y et créez un src/sagasdossier. Créer leindex.jsfichier et placez le code ci-dessous dans ce fichier.

Dans le fichier ci-dessus, j'importe d'abord forkdepuis effectsetwatchUserAuthenticationfrom watchers- qui n'existe pas encore mais nous créerons ce fichier ensuite. Ensuite, j'exporte simplement une fonction de générateur et je fork le fichier watchUserAuthentication.

Maintenant, créez un watcher.jsfichier dans le même dossier que ci-dessus et placez le code ci-dessous dans ce fichier.

Encore une fois, j'importe takeLatesteffet à partir de redux-saga, puis à registerSagapartir authenticationSaga.jsduquel nous allons créer ensuite. Ensuite, importez en actions/index.jstant que types.

J'exporte une fonction de générateur qui surveille essentiellement l' REGISTER_USERaction et effectue un appel registerSaga.

Maintenant, créons la authenticatioSaga.jssaga dans le même dossier que ci-dessus et placez le code ci-dessous dans ce fichier.

Dans cette saga, j'importe quelques autres effets - putet calldepuis redux-saga. Puis registerUserServiceest importé de service/authenticationService.js. J'importe toutes les actions en tant que types à partir de actions/index.js. Ensuite, j'exporte la fonction générateur registerSaga.

Cette fonction est responsable de l'appel registerUserService, ce qui fait un appel ajax à notre serveur pour enregistrer un nouvel utilisateur - que j'écrirai après cette étape. Il reçoit une réponse registerUserServiceet met l' REGISTER_USER_SUCCESSaction. S'il y a une erreur, il met l' REGISTER_USER_ERRORaction.

Importez les sagas

Maintenant que nous avons nos sagas, il est temps de les importer dans notre magasin. Ouvrez store/configureStore.jset mettez à jour son contenu avec le contenu ci-dessous.

Ici j'importe createSagaMiddleware, rootReduceret rootSaga. Ensuite, à l'intérieur de la configureStorefonction, je crée un nouveau sagaMiddlewareet le passe à l' createStoreaide de la applyMiddlewarefonction. Enfin, j'exécute le rootSaga.

Il est maintenant temps de créer le src/servicesdossier et de créer un nouveau premier service. Nomme leauthenticationService.jset placez le code ci-dessous dans ce service.

Ce fichier effectue une requête ajax de base en utilisant Fetch API avec certains paramètres et en-tête. C'est un service assez explicite.

Réducteur

Maintenant que nous faisons une demande au serveur, il est temps de recevoir cette réponse dans notre composant. Pour ce faire, nous avons besoin d'un réducteur . Allez-y et créez unreducers/registerReducer.jsfichier et placez-y le code ci-dessous.

C'est une simple fonction de réduction qui obtient l'état et retourne un nouvel état. Il vérifie pour REGISTER_USER_SUCCESSet REGISTER_USER_ERRORactions, et renvoie le nouvel état du composant.

Maintenant, allez-y et ouvrez le src/reducers/index.jsfichier et mettez-le à jour avec le contenu suivant.

En cela, rootReducerje vais importer tous les réducteurs, puis les combiner avant de les exporter. C'est exactement ce que je fais register.

Exécution du code mis à jour

Nous avons maintenant terminé le processus d'inscription. Il est temps d'actualiser votre navigateur, d'accéder à l'itinéraire des registres et de saisir des données. Si vous entrez un e-mail existant, vous devriez voir le résultat ci-dessous.

Si vous entrez un nouvel e-mail, vous devriez être redirigé vers loginPage, ce que nous allons implémenter ensuite.

S'identifier

Il est temps pour nous de connecter l'utilisateur après son enregistrement. Allez-y et ouvrezcomponents/loginPage.jsfichier et mettez-le à jour avec le contenu suivant.

Ce composant est à peu près le même que registerPage. La seule différence est qu'il envoieloginUserActionque nous allons écrire ensuite. Une autre différence est que, si la réponse du serveur aboutit, je recevrai un fichier JWT token. Je stocke ce jeton localStorage. Vous pouvez utiliser une méthode différente, mais pour cet exemple, j'utilise cette approche.

Allez-y et ouvrez actions/authenticationActions.jset mettez-le à jour avec le contenu suivant.

Ici, j'exporte la nouvelle loginUserActionfonction avec le LOGIN_USERtype d'action et user payload.

Avant d'aller de l'avant, ouvrez le actions/index.jsfichier et mettez à jour son contenu avec ce qui suit.

Maintenant, allez-y et ouvrez le sagas/watchers.jsfichier et mettez à jour son contenu avec ce qui suit.

Ici, je suis simplement en train d'importer loginSagaet de l'appeler quand il reçoit leLOGIN_USERaction.

Nous n'avons pas loginSagaencore. Pour cette raison, allez-y et ouvrez lesagas/authenticationSaga.jssaga et mettre à jour son contenu avec ce qui suit.

Ici , je suis l' importation d' un service supplémentaire - loginUserService, que j'implantera à côté - puis exporter la nouvelle fonction de générateur nommé loginSaga, ce qui fait à peu près la même chose que registerSaga.

Ouvrez maintenant le services/authenticationService.jsservice et mettez à jour son contenu avec ce qui suit.

Ici, j'ajoute loginUserService qui fait à peu près la même chose que registerUserService, c'est-à-dire l'envoi d'une demande ajax pour se connecter à l'utilisateur.

Maintenant que nous avons réussi à envoyer une demande au serveur, il est temps de recevoir une réponse de notre serveur à notre composant de connexion. Pour cela, créez un nouveau réducteur reducers / loginReducer.js et placez-y le code ci-dessous.

Cela fait à peu près la même chose que registerReducer- écouter LOGIN_USER_SUCCESSet LOGIN_USER_ERRORactions, et retourner le nouvel état.

Ouvrez maintenant le reducers/index.jset mettez à jour son contenu avec le code ci-dessous.

Ici, je l'importe loginReduceret je le combine avec registeravant de le renvoyer sous forme de fichier rootReducer.

Après cela, actualisez votre navigateur et entrez un e-mail qui n'est pas encore enregistré. Après avoir appuyé sur le bouton de connexion, vous devriez voir le résultat ci-dessous.

Si vous entrez un e-mail enregistré, la demande devrait aboutir, mais vous ne devriez encore rien voir, car je n'ai pas implémenté le dashboardPagecomposant. Cela ne sera accessible qu'après une authentification réussie. Cela dit, mettons-le en œuvre.

Page du tableau de bord

Créez maintenant le components/dashboardPage.jscomposant et placez le code ci-dessous dans ce composant.

C'est un composant très simple - il ne fait que renvoyer le Dashboardtexte.

Ouvrez maintenant le routes/index.jsroute et mettez à jour son contenu avec ce qui suit.

Ici, je fais de nouvelles choses. D'abord, j'importe un dashboardPageet je l'ajoute à route. Quand ledashboardroute est accédée, la requireAuthfonction sera déclenchée. Cette fonction vérifie si l'utilisateur l'est loggedInou non. Pour vérifier cela, je cherchetokendans localStorage, que j'ai stocké dans le loginPagecomposant lors d'une connexion réussie. S'il existe, il dashboardPageest rendu à l'utilisateur.

Maintenant, lorsque vous actualisez la page dans votre navigateur, entrez un e-mail enregistré et appuyez sur Entrée, vous devriez voir les résultats ci-dessous.

Alors voilà, il s'agit d'un système de connexion complet utilisant React, Redux et Redux-Saga. Si vous souhaitez voir l'ensemble du projet, clonez ce référentiel.

J'espère que vous avez apprécié ce post.