Creación de autenticación basada en token usando NodeJs y RethinkDB

Introducción

En este tutorial, aprenderemos cómo implementar la autenticación basada en tokens en Node.js usando JWT. La autenticación basada en token es un enfoque muy popular en la parte de autenticación de la aplicación. Ha sido implementado y utilizado por una variedad de servicios web populares.

DESCARGAR

¿Qué es la autenticación basada en token?

Generalmente, realizamos la autenticación de una aplicación web manteniendo la sesión en el servidor y usamos cookies en el extremo del cliente para realizar el seguimiento de la sesión.

Esto limita la escalabilidad del sistema a la web, ya que las aplicaciones móviles generalmente no admiten ni funcionan con cookies.

Además, las cookies no son seguras y se pueden utilizar para realizar ataques de falsificación entre sitios. Quiero que la teoría sea breve, puedes obtener más información en este documento de w3.org.

Nuestro proyecto

Construiremos el sistema de autenticación simple usando Node.js y RethinkDB con, por supuesto, autenticación basada en token. Esto es lo que haremos:

  • Configuración del proyecto.
  • Creando la base de datos y la tabla de RethinkDB.
  • Desarrollando autenticación basada en tokens en Node.js usando JWT.

Así que vamos a sumergirnos.

Configurar el proyecto

Inicie el nuevo proyecto con el comando npm init .

npm init –y

Aquí está mi archivo package.JSON inicial.

{
  “nombre” : “autenticación basada en token” ,
  “versión” : “1.0.0” ,
  “descripción” : “” ,
  “main” : “index.js” ,
  “scripts” : {
    “prueba” : ” echo “ Error : no se especificó la prueba ” && exit 1 ”
  } ,
  ” palabras clave ” : [ ] ,
  ” autor ” : ” ” ,
  ” licencia ” : ” ISC “
}

Instalemos la dependencia que necesitamos para implementar nuestro sistema.

npm i –S express body-parser async jsonwebtoken rethinkdb

Una vez instaladas las dependencias, podemos avanzar para codificar nuestro proyecto. Aquí está la estructura del directorio del proyecto.

Estructura de carpetas

+ controladores

+ middlewares


+ modelos


+ node_modules


– config.json


– package.json


– app.js

Creemos una base de datos en RethinkDB.

Creando la base de datos y la tabla de RethinkDB

Supongo que ha instalado RethinkDB en su sistema. Si no es así, no es gran cosa hacerlo. Siga nuestro tutorial de introducción a RethinkDB para comprender el concepto de esta increíble tecnología de base de datos.

Si ya lo tiene, inicie su servidor RethinkDB y abra la consola de administración web apuntando a http: // localhost: 8080 .

Primero, cree una nueva base de datos.

Luego crea una tabla en ella.

Bien, la base de datos de RethinkDB está configurada y ahora podemos hacer cosas reales y codificar nuestro proyecto.

Desarrollo de autenticación basada en tokens en Node.js usando JWT

Vamos a utilizar el módulo de nodo de token web JSON para aprovechar la autenticación basada en token. Es un módulo realmente fácil y muy útil. Antes de pasar a la codificación, déjame mostrarte cómo va a funcionar el sistema.

Paso 1: el cliente realiza el inicio de sesión y, si tiene éxito, se genera un nuevo token. Esta API no debe realizar la validación de tokens, en su lugar, necesita generar token.

Paso 2: el cliente realiza una solicitud a otras API y proporciona el token en la cadena de consulta, el cuerpo de la solicitud o el encabezado HTTP.

Paso 3: El servidor realiza validaciones de token si el token es válido, luego se procesa la solicitud y se envía la respuesta al cliente.

Esto parece muy fácil en Express.js. Lo único que tenemos que hacer es tener un middleware que realice la validación del token. Colocaremos todas aquellas API que no requieren validación de token (como inicio de sesión) arriba en este middleware y todas las que sí requieren validación de token, las colocaremos después del middleware.

Basta de hablar. Codifiquemos. Aquí está nuestro código de servidor de nodo.

app.js
var express = require ( ‘express’ ) ;
var bodyParser = require ( ‘body-parser’ ) ;
var app = express ( ) ;

global.
config = require ( ‘./config’ ) ;


aplicación.
use ( bodyParser. json ( ) ) ;

aplicación.
use ( bodyParser. urlencoded ( { extendido : falso } ) ) ;

aplicación.
use ( require ( ‘./controllers’ ) ) ; // Las rutas que no requieren autenticación de token deben colocarse aquí

app.
use ( require ( ‘./middlewares/TokenValidator’ ) ) ; // middleware para autenticar la

aplicación de
token .
use ( require ( ‘./controllers/account’ ) ) ; // Las apis para proteger y usar el token deben colocarse aquí


aplicación.
escuchar ( puerto de configuración , función( ) {

  consola.
log ( “Escuchando en el puerto” + puerto de configuración ) ;
} ) ;

Observe que en nuestro código, tenemos middleware que realiza la validación de tokens y tenemos dos API, una para realizar el inicio de sesión y otra para mostrar los detalles de la cuenta. Por supuesto, los detalles de la cuenta deben mostrarse si el usuario es válido, es decir, tiene un token válido, por lo que colocamos esta API debajo del middleware y el inicio de sesión, lo que a su vez genera el token colocado antes del middleware.

Aquí está nuestro archivo de configuración.

config.json
{
  “puerto” : 3000 ,
  “secreto” : “ssssshhhhh”
}

Ahora echemos un vistazo a los controladores. Tenemos una carpeta de controlador que se encarga de la generación de tokens. Aquí está el código para lo mismo.

controladores / index.js
var express = require ( ‘express’ ) ;
var router = express. Enrutador ( ) ;

/ **

  * @description


  * La primera ruta manejará la entrega del archivo html estático.


  * La segunda ruta manejará las llamadas a la API.


* /


enrutador.
get ( ‘/’ , function ( req , res ) {

  res.
json ( { message : “Hello World” } ) ;
} );


enrutador.
use ( ‘/ usuario’ , require ( ‘./user’ ) ) ;


módulo.
exportaciones = enrutador ;

Este archivo actúa como un punto de entrada para administrar otras rutas. Encontré esta forma más limpia de administrar rutas rápidas. Déjame saber si tienes una mejor manera en los comentarios.

Aquí está el enrutador del usuario.

controladores / user.js
var express = require ( ‘express’ ) ;
var router = express. Enrutador ( ) ;
var db = require ( ‘../models/db’ ) ;
var jwt = require ( ‘jsonwebtoken’ ) ;


enrutador.
post ( ‘/’ , function ( req , res ) {
  // Crear nuevo usuario.
  var data = {

    email
: req. cuerpo . emailAddress ,

    contraseña
: req. cuerpo . contraseña
  } ;
  var modelo = nuevo db ( ) ;

  modelo.
addNewUser ( data , function ( error , response ) {
    if ( error ) {
      return res. json ( { “error” : true , “message” : error} )
    }

    res.
json ( { “error” : falso , “mensaje” : “Nuevo usuario agregado” } ) ;
  } ) ;
} ) ;


enrutador.
post ( ‘/ login’ , function ( req , res ) {
  var model = new db ( ) ;
  // realizar el

  modelo de
inicio de sesión del usuario .
findUser ( req. body . emailAddress, función ( error , respuesta ) {
    if ( error ) {
      return res. json ( { “error” : verdadero , “mensaje” : error } ) ;
    }
    if ( ! respuesta ) {
      return res. json ( { “error” : true , “message” : “Usuario no encontrado” } ) ;
    }
    si (respuesta. contraseña ! == req. cuerpo . contraseña ) {
      return res. json ( { “error” : true , “message” : “Contraseña incompatible” } ) ;
    }
    var token = jwt. sign ( respuesta , global. config . secret , {

        expiresIn
: 1440 // expira en 1 hora
    } ) ;


    res.
JSON ({

        error
: falso ,

        mensaje
: ‘¡Validación exitosa!’ ,

        token
: token
    } ) ;
  } ) ;
} ) ;

módulo.
exportaciones = enrutador ;

En la primera ruta, estamos creando un nuevo usuario usando nuestra función modelo addNewUser () que veremos en un momento. Tras la creación exitosa del usuario, devolvemos la respuesta.

En la segunda ruta, estamos validando al usuario contra la base de datos y, si se encuentra, estamos generando un nuevo token web usando la función JWT, aquí estamos pasando nuestro secreto que debería ser fuerte en producción. De hecho, puede usar claves TLS para realizar el cifrado del token.

En aras de la simplicidad y la demostración, estoy usando una clave simple, pero no se recomienda para la producción.

Así que veamos los modelos ahora. Primero nuestra función es addNewUser () . Aquí está.

modelos / db.js
“uso estricto” ;
var rethinkdb = require ( ‘rethinkdb’ ) ;
var async = require ( ‘async’ ) ;
class db {

  connectToDb
( devolución de llamada ) {

    rethinkdb.
connect ( {

      host
: ‘localhost’ ,

      port
: 28015 ,

      db
: ‘users’
    } , function ( err , connection) {

      devolución de llamada
( err , conexión ) ;
    } ) ;
  }


  addNewUser
( userData , devolución de llamada ) {
    var self = this ;

    async.
cascada ( [
      function ( callback ) {

        self.
connectToDb ( ( err , connection ) => {
          if ( err ) {
            return callback( verdadero , “Error al conectarse a la base de datos” ) ;
          }

          devolución de llamada
( nulo , conexión ) ;
        } ) ;
      } ,
      función ( conexión , devolución de llamada ) {

        rethinkdb.
table ( ‘inicio de sesión’ ) . insertar (datos de usuario ) . ejecutar ( conexión , función ( err , resultado ) {

            conexión.
cerrar ( ) ;
            if ( err ) {
              return callback ( verdadero , “Ocurre un error al agregar un nuevo usuario” ) ;
            }

            devolución de llamada
( nulo , resultado ) ;
        } ) ;
      }
    ] , function ( err , data ) {

      callback
( err === null ? false : true , data ) ;
    }) ;
  }


  findUser
( emailAddress , callback ) {
     ——————————-
  }
}


módulo.
exportaciones = db ;

Aquí primero nos estamos conectando a la base de datos RethinkDB y luego insertando un nuevo documento en ella. Asegúrese de liberar siempre la conexión después de la ejecución de la consulta.

Aquí está la función findUser () .

modelos / db.js
“uso estricto” ;
var rethinkdb = require ( ‘rethinkdb’ ) ;
var async = require ( ‘async’ ) ;
class db {

  connectToDb
( devolución de llamada ) {

    rethinkdb.
connect ( {

      host
: ‘localhost’ ,

      port
: 28015 ,

      db
: ‘users’
    } , function ( err , connection) {

      devolución de llamada
( err , conexión ) ;
    } ) ;
  }


  findUser
( emailAddress , callback ) {
    var self = this ;

    async.
cascada ( [
    function ( callback ) {

      self.
connectToDb ( ( err , connection ) => {
        if ( err ) {
          return callback( verdadero , “Error al conectarse a la base de datos” ) ;
        }

        devolución de llamada
( nulo , conexión ) ;
      } ) ;
    } ,
    función ( conexión , devolución de llamada ) {

      rethinkdb.
table ( ‘inicio de sesión’ ) . filter ( { “email” : emailAddress } ) . ejecutar ( conexión , función ( err , cursor) {

        conexión.
cerrar ( ) ;
        if ( err ) {
          return callback ( verdadero , “Error al obtener el usuario de la base de datos” ) ;
        }

        cursor.
toArray ( function ( err , result ) {
          if ( err ) {
            return callback ( true , “Error al leer el cursor” ) ;
          }
          // Suponiendo que el correo electrónico será la clave principal y única

          devolución de llamada
( nulo , resultado [ 0 ] ) ;
        } ) ;
      } ) ;
    }
    ] , function ( err , data ) {

      callback
( err === null ? false : true , data ) ;
    } ) ;
  }


  addNewUser
( userData , devolución de llamada ) {
    ———————————–
  }
}


módulo.
exportaciones = db ;

Aquí estamos usando el comando filter () ReQL para averiguar la dirección de correo electrónico y devolver el resultado. No es gran cosa aquí.

Examinemos el middleware para validar el token en cada solicitud.

Middleware para validar el token

Aquí está nuestro código de middleware.

middlewares / TokenValidator.js
var jwt = require ( ‘jsonwebtoken’ ) ;


módulo.
exportaciones = función ( req , res , siguiente ) {
  var token = req. cuerpo . token || req. consulta . token || req. encabezados [ ‘x-access-token’ ] ;
  // decodifica el token
  if ( token ) {
    // verifica el secreto y verifica exp

    jwt.
verificar( token , global. config . secret , function ( err , decodificado ) {
        if ( err ) {
            return res. json ( { “error” : true , “message” : ‘No se pudo autenticar el token.’ } ) ;
        }

      req.
decodificado = decodificado ;

      siguiente
( ) ;
    } ) ;
  } más {
    // si no hay token
    // devuelve un error
    devuelve res. estado ( 403 ) . send ( {
        “error” : true ,
        “message” : ‘No se proporcionó token.’
    } ) ;
  }
}

Esta es la parte principal del código. Aquí estamos verificando todas las fuentes desde donde posiblemente podría llegar el token, como la cadena de consulta, el cuerpo de la solicitud y el encabezado.

Al recibirlo, lo estamos verificando usando nuestro token secreto y entrante. El boom, eso es todo 🙂 Si tiene éxito, nos moveremos a la siguiente ruta; de lo contrario, devolveremos la respuesta de error.

Ejecutando el código

Para ejecutar el código, asegúrese de que RethinkDB esté en funcionamiento. Todo lo que necesita hacer es ejecutar el siguiente comando en la terminal.

repensar

Debería ver una pantalla similar a la que se muestra a continuación.

Ahora cambie a la carpeta del proyecto y ejecute el servidor usando el siguiente comando.

nodo app.js

El servidor está escuchando en el puerto especificado.

Para acceder a la API, abra su simulador de API. Recomendamos Postman.

Creando nuevo usuario

Pulse la solicitud POST a localhost: 3000 / users con los datos de la solicitud que se muestran a continuación.

Generar token de acceso O iniciar sesión

Una vez que se crea el usuario, presione la solicitud POST a localhost: 3000 / user / login con los datos de la solicitud que se muestran a continuación.

Como puede ver, ahora tenemos la ficha con nosotros.

Accediendo a las API mediante token

Como hemos comentado en la sección anterior, podemos pasar el token en la cadena de consulta, el cuerpo de la solicitud y en el encabezado según el tipo de solicitud HTTP.

Aquí estoy mostrando el formato de la cadena de consulta, también puede verificarlo con el encabezado.

Nota: el nombre del encabezado es x-access-token y el valor es una cadena de token.

Intente poner un token incorrecto o ningún token y debería recibir un error.

Eso es todo, acabamos de construir nuestro sistema de autenticación básico basado en tokens.

Conclusión

Hemos construido nuestra autenticación básica basada en tokens que es escalable a través de dispositivos móviles y web. Puede tomar este código de Github y modificarlo según sus necesidades.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *