Cómo configurar la autenticación de usuario usando React, Redux y Redux Saga

ACTUALIZACIÓN (12.02.2019): Recientemente actualicé este proyecto con los enrutadores react más recientes, es decir, la versión 4.3.1, que es react-router-dom. Dirígete a su repositorio para ver los cambios.

En mi blog anterior escribí cómo escribir una arquitectura escalable en Node.js. Como utilicé a cartero para probar el funcionamiento de esa plataforma, pensé que sería una buena idea tener su implementación del lado del cliente. Para escribir su lado del cliente, decidí usar la pila de tecnología a continuación:

  • Reaccionar
  • Redux
  • Redux-Saga
  • Reaccionar enrutador

Esta publicación asume que ya conoces los conceptos básicos y de reacción de Redux y Redux-Saga.

Empezando

Clonar el repositorio de mi blog anterior. CDen su carpeta raíz y ejecutar npm install. Esto instalará todas las dependencias.

En segundo lugar, instale mongodben su máquina. Una vez instalado, ejecute el servidor mongo usando elmongodcomando en su terminal, si no se inicia como un servicio en su máquina.

A continuación, asegúrese de que el paquete nodemon esté instalado en su máquina a nivel mundial . Vaya a la carpeta del lado del servidor y ejecutenodemon index.jspara ejecutar el servidor backend.

Ahora que nuestro backend está en funcionamiento, es hora de pasar a la implementación del lado del cliente.

Si aún no lo ha instalado create-react-appluego continúe instálelo usando el siguiente comando.

npm install create-react-app -g

Este comando se instalará create-react-appa nivel mundial .

Crea el proyecto

Ahora es el momento de crear un proyecto. Utilizar:

create-react-app react-login

Esto creará un nuevo proyecto con el nombre react-login. Continúe y entre cden esa carpeta. Abre tupackage.jsonarchivo en su editor favorito y agregue las siguientes dependencias:

No necesitamos propiedades adicionales en este package.jsonarchivo. Podemos simplemente eliminarlos, pero lo dejaré como está y seguiré adelante para que lleguemos a la parte interesante de este blog.

Ahora simplemente ejecute:

npm install

que instalará todas las dependencias que mencionamos anteriormente.

Archivo de índice

Para empezar, abra el index.jsy coloque el código siguiente en este archivo.

En este código estamos importando reacty react-dom. Luego importamos Routery browserHistorydesde react-router. Estos son necesarios para fines de enrutamiento, que usaré más adelante en elroutes/index.jsarchivo. A continuación, importamos Provider, esto se usa para proporcionar almacenamiento a los componentes secundarios.

configureStorey routesson algo que vamos a importar a continuación y que implementaré en un segundo. Simplemente impórtelos como están y utilícelos en este archivo como se muestra arriba.

Ahora nuestro archivo de índice está configurado.

Configuración de la tienda

Crea una nueva carpeta llamada storedentro de srccarpeta. Dentro de esa nueva carpeta, cree un archivo llamado configureStore.js,y pegue el siguiente código en ese archivo.

Primero estamos importando createStore, que se utilizarán para createStore, y applyMiddlewareque se utilizarán para aplicar middlewares a nuestra tienda - sagas en este caso, pero lo veremos más adelante en este blog - desde redux.

Luego importamos rootReducer, lo crearemos más tarde. Por ahora, simplemente impórtelo y utilícelo como está. A esto le sigue la función configureStore, que devuelve un objeto llamando a la createStorefunción y pasando rootReducercomo parámetro.

Finalmente, export configureStorepone a configureStoredisposición en el index.jsarchivo, construido anteriormente.

Ahora que está fuera de nuestro camino, siga adelante y cree el src/reducerscarpeta, cree el archivo index.js y pegue el código siguiente en este archivo.

Este archivo se encarga de importar el resto de reductores dentro de la carpeta de reductores, combinarlos y exportarlos para que estén disponibles para su uso configureStore.js. Haremos cambios en este archivo cuando agreguemos nuevos reductores más adelante en este blog.

Archivo de enrutamiento

Hora del archivo de rutas. Adelante, crea elsrc/routescarpeta y dentro de esta carpeta cree una index.jsarchivo. Ahora ábrelo y pega el siguiente código.

El objetivo principal de este archivo es manejar el enrutamiento en nuestro proyecto. Las importaciones de archivos React, Routey IndexRoute. Después de eso, necesitamos un contenedor, en este caso estoy importando container/App, que escribiremos pronto. El siguiente es RegisterPage, que es un componente, y lo escribiremos también.

En el padre Route, cuando la ruta de inicio coincide, simplemente representamos nuestro Appcontenedor. Los IndexRouteusuarios verán RegisterPagecuál se representará dentro del Appcontenedor.

Envase

Ahora es el momento del contenedor. Continúe y cree una nueva carpeta llamada container. Dentro de esta carpeta, cree un nuevo archivo llamado App.jsy coloque el siguiente código en este archivo.

Esto es bastante sencillo. El propósito principal de este archivo es renderizar el resto de los componentes.{this.props.children}sirve para este propósito.

Registro

Ahora es el momento de registerPage. Crear una nueva carpetasrc/componentsy crea un componente dentro de la carpeta de componentes llamadoregisterPage.js. Pegue el siguiente código en este componente.

Por ahora, este es un componente muy simple. Editaremos esto más tarde para agregar un formulario de registro y ponerle algunas funciones.

Salida

Después de crear todas las carpetas y archivos anteriores, ejecútelo npm starten su proyecto y abra//localhost:3000en su navegador. Debería poder ver el resultado a continuación.

Al hacer clic en iniciar sesión aquí no se redirigirá a la ruta de inicio de sesión que arreglaremos a continuación.

Haciendo que funcione

Enrutamiento

Para que el enrutamiento funcione, primero cree un nuevo componente dentro de la carpeta de componentes. Nómbrelo loginPage.jsy coloque el siguiente código dentro de este componente.

Este componente es muy simple. Presenta contenido básico y un enlace para registrar el componente.

Ahora abra el routes.jsarchivo, que ya creamos anteriormente, y realice los siguientes cambios.

Cambie la ruta del índice a LoginPageporque queremos que los usuarios accedan al componente de inicio de sesión cuando visiten la página de inicio. Antes de hacer eso, impórtelo desde la carpeta de componentes.

Ahora actualice su navegador y debería poder ver loginPageprimero. Al hacer clic en el enlace "Registrarse aquí", registerPagedebería aparecer.

Ahora tenemos las rutas básicas funcionando.

Inicio de sesión y registro

Registro

Para que el proceso de inicio de sesión funcione, primero manejaré el proceso de registro para que agreguemos algunos usuarios a nuestra base de datos. Así que vamos a abrirlo components/registerPage.jsy actualizarlo con los siguientes contenidos.

Parece que ahora hay mucho código en este archivo, pero todo es simple. Primero estamos importandoconnectpara conectar nuestro storecon elregisterPagecomponente. Entonces importamosregisterUserActionque escribiremos a continuación.

Dentro de la renderfunción, primero verifico la respuesta del servidor si existe, luego asigno las propiedades de éxito y mensaje que se reciben del servidor. Esta puede ser una función separada pero, en aras de la simplicidad, las coloqué en la renderfunción.

A continuación hay un formulario de registro. Cuando el usuario hace clic en el botón de registro, activa la onHandleRegistrationfunción que obtiene los datos ingresados ​​por el usuario del formulario, ydispatch registerUserActioncon sus datos como parámetros. Vamos a escribir acciones en el siguiente paso.

Para que el código anterior funcione, necesitamos mapStateToProps, como lo estamos haciendo en la parte inferior del componente, y luego conectarlo con el registerPagecomponente al final.

Comportamiento

Ahora es el momento de agregar acciones. Adelante, crea elsrc/actionscarpeta. Crea elindex.jsarchivo y coloque el siguiente código en él.

Este código exporta algunas constantes que usaremos a lo largo de nuestro proyecto.

Ahora adelante y crea el authenticationActions.jsarchivo dentro de la misma carpeta y coloque el siguiente código en él.

Aquí estoy importando el archivo de índice, que exporta constantes, y luego export registrationUserActiondevuelvo un objeto con tipo de acción y datos de usuario. El tipo de acción en este caso es REGISTER_USER. Esta acción se enviará cuando un usuario intente registrarse, y estará disponible a lo largo de nuestro proyecto que escucharemos en nuestras sagas.

Sagas

Ahora estamos en la etapa en la que podemos introducir nuestras sagas en nuestro proyecto. Si es nuevo en Redux-Saga, le sugiero que lea este blog antes de continuar.

Si ya conoces las sagas, sigue adelante y crea un src/sagascarpeta. Crea elindex.jsy coloque el siguiente código en este archivo.

En el archivo anterior, primero estoy importando forkdesde effectsywatchUserAuthenticationfrom watchers- que aún no existe pero crearemos ese archivo a continuación. Luego, simplemente exporto una función de generador y bifurco el archivo watchUserAuthentication.

Ahora siga adelante y cree un watcher.jsarchivo en la misma carpeta que arriba, y coloque el siguiente código en este archivo.

De nuevo, importo takeLatestefecto desde redux-saga, luego registerSagadesde authenticationSaga.js, que crearemos a continuación. A continuación, importe actions/index.jscomo tipos.

Estoy exportando una función de generador que básicamente observa la REGISTER_USERacción y realiza una llamada a registerSaga.

Ahora creemos la authenticatioSaga.jssaga en la misma carpeta que la anterior y coloquemos el siguiente código en este archivo.

En esta saga estoy importando un par de efectos más, puty callde redux-saga. Luego registerUserServicese importa de service/authenticationService.js. Estoy importando todas las acciones como tipos de actions/index.js. Entonces estoy exportando la función del generador registerSaga.

Esta función es responsable de llamar registerUserService, que realiza una llamada ajax a nuestro servidor para registrar un nuevo usuario, que escribiré después de este paso. Recibe una respuesta registerUserServicey pone la REGISTER_USER_SUCCESSacción. Si hay un error, pone la REGISTER_USER_ERRORacción.

Importar las sagas

Ahora que tenemos nuestras sagas es el momento de importarlas en nuestra tienda. Abra store/configureStore.jsy actualice su contenido con los siguientes contenidos.

Aquí Estoy importando createSagaMiddleware, rootReducery rootSaga. Luego, dentro de la configureStorefunción, estoy creando una nueva sagaMiddlewarey pasándola a createStoreusar la applyMiddlewarefunción. Finalmente, estoy ejecutando el rootSaga.

Ahora es el momento de crear la src/servicescarpeta y crear un nuevo primer servicio. NombraloauthenticationService.jsy coloque el siguiente código en este servicio.

Este archivo realiza una solicitud ajax básica utilizando la API de recuperación con algunos parámetros y encabezado. Es un servicio bastante autoexplicativo.

Reductor

Ahora que estamos haciendo una solicitud al servidor, es hora de recibir esa respuesta en nuestro componente. Para hacer esto necesitamos un reductor . Adelante, crea unreducers/registerReducer.jsarchivo y coloque el siguiente código en él.

Es una función reductora simple que obtiene el estado y devuelve un nuevo estado. Se comprueba para REGISTER_USER_SUCCESSy REGISTER_USER_ERRORacciones, y devuelve el nuevo estado del componente.

Ahora adelante y abre el src/reducers/index.jsarchivo y actualícelo con el siguiente contenido.

En esto rootReducer, importaré todos los reductores y luego los combinaré antes de exportar. Eso es exactamente lo que estoy haciendo register.

Ejecutando el código actualizado

Ahora hemos terminado con el proceso de registro. Es hora de actualizar su navegador, ir a la ruta de registro e ingresar algunos datos. Si ingresa un correo electrónico existente, debería ver el resultado a continuación.

Si ingresa un nuevo correo electrónico, debería ser redirigido a loginPage, que implementaremos a continuación.

Iniciar sesión

Es hora de que iniciemos sesión como usuario después de que esté registrado. Adelante, abrecomponents/loginPage.jsarchivo y actualícelo con el siguiente contenido.

Este componente es prácticamente el mismo que registerPage. La única diferencia es que despachaloginUserActionque vamos a escribir a continuación. Otra diferencia es que, si la respuesta del servidor es correcta, recibiré un JWT token. Estoy almacenando esa ficha localStorage. Puede usar un método diferente, pero para este ejemplo estoy usando este enfoque.

Adelante, abre actions/authenticationActions.jsy actualizarlo con los siguientes contenidos.

Aquí estoy exportando la nueva loginUserActionfunción con el LOGIN_USERtipo de acción y user payload.

Antes de seguir adelante, abra el actions/index.jsarchivo y actualice su contenido con lo siguiente.

Ahora adelante y abre el sagas/watchers.jsarchivo y actualice su contenido con lo siguiente.

Aquí simplemente lo estoy importando loginSagay llamándolo cuando recibe elLOGIN_USERacción.

loginSagaAún no lo tenemos . Por esa razón adelante y abre elsagas/authenticationSaga.jssaga y actualice su contenido con lo siguiente.

Aquí estoy importando un servicio adicional loginUserService, que implementaré a continuación, y luego exporto la nueva función de generador llamada loginSaga, que hace prácticamente lo mismo que registerSaga.

Ahora abre el services/authenticationService.jsservicio y actualice su contenido con lo siguiente.

Aquí estoy agregando loginUserService que hace más o menos lo mismo que registerUserService, es decir, enviar una solicitud ajax para iniciar sesión como usuario.

Ahora que hemos enviado con éxito una solicitud al servidor, es hora de recibir una respuesta de nuestro servidor a nuestro componente de inicio de sesión. Para eso, cree un nuevo reductor / loginReducer.js reducer y coloque el siguiente código en él.

Lo hace más o menos lo mismo que registerReducer- escuchar LOGIN_USER_SUCCESSy LOGIN_USER_ERRORacciones, y devolviendo el nuevo estado.

Ahora abre el reducers/index.jsarchivo y actualice su contenido con el siguiente código.

Aquí lo estoy importando loginReducery combinándolo registerantes de devolverlo como rootReducer.

Después de esto, actualice su navegador e ingrese un correo electrónico que aún no esté registrado. Después de presionar el botón de inicio de sesión, debería ver el resultado a continuación.

Si ingresa un correo electrónico registrado, la solicitud debería ser exitosa, pero no debería ver nada todavía, ya que no he implementado el dashboardPagecomponente. Solo se accederá después de una autenticación exitosa. Dicho esto, implementémoslo.

Página del panel

Ahora crea el components/dashboardPage.jscomponente y coloque el siguiente código en este componente.

Este es un componente muy simple, todo lo que hace es devolver el Dashboardtexto.

Ahora abre el routes/index.jsenrutar y actualizar su contenido con lo siguiente.

Aquí estoy haciendo algunas cosas nuevas. Primero, estoy importando dashboardPagey agregando route. Cuando eldashboardse accede a la ruta, la requireAuthfunción se activará. Esta función comprueba si el usuario lo es loggedIno no. Para comprobar eso, estoy buscandotokenin localStorage, que guardé en el loginPagecomponente al iniciar sesión correctamente. Si existe, se dashboardPagemuestra al usuario.

Ahora, cuando actualice la página en su navegador, ingrese un correo electrónico registrado y presione enter, debería ver los resultados a continuación.

Así que ahí está, este es un sistema de inicio de sesión completo que usa React, Redux y Redux-Saga. Si desea ver el proyecto completo, clone este repositorio.

Espero que hayas disfrutado esta publicación.