No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

No se trata de lo que quieres comprar, sino de quién quieres ser. Invierte en tu educación con el precio especial

Antes: $249

Currency
$209

Paga en 4 cuotas sin intereses

Paga en 4 cuotas sin intereses
Suscríbete

Termina en:

12 Días
13 Hrs
11 Min
15 Seg

Implemetando login con Passport.js

7/20
Recursos

Aportes 27

Preguntas 4

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

Solución de error con Passport.Js

En el momento de nosotros loguearnos nos lanza el siguiente error 👇🏽

message": "req.logIn is not a function",

para poder solucionar este error sin tener que bajar nuestra version de passport podemos hacer lo siguiente 👨‍💻

Index.js

const passport = require('passport')
// Antes de nuestras rutas debemos de colocar esto
app.use(passport.initialize());
// Rutas
routerApi(app);

Esto sucede ya que debemos de inicializar el middleware de passport antes de nuestras rutas

y ahora todo deberia de funcionar con normalidad 🥳

Passport.js es una serie de librerías y estrategias que nos brinda para hacer la capa de autenticación, permite generar varias estrategias (twitter, github, facebook, etc.) teniendo un código base para logearnos de diferentes maneras.

Página oficial https://www.passportjs.org/

  • Instalando passport: npm i passport

  • passport-local permite hacer un login básico usando username y password, su instalación es: npm install passport-local

Se crea la carpeta utils/auth/strategies donde se colocarán las estrategias a implementar.

Se crea el archivo local.strategy.js, ahí se crea una instancia de Strategy la cual recibe una función callback con la lógica de negocio. Recibe tres parámetros: email, password y la función done que se usará cuando todo salga bien o mal.

En este mismo archivo se crea una serie de validaciones, en primer lugar valida si existe el email y en segundo lugar valida si la password es correcta.

Para la primera validación se busca el email y si no se encuentra, se ejecuta la función done lanzando un error de tipo boom (unauthorized) con un false (no se pudo hacer la validación).

En la segunda validación ya se encontraron los datos de usuario en la base de datos, por lo tanto, verifica que la contraseña que envía el usuario sea la misma que la que se encuentra en la BD (hace una comparación). Si las contraseñas no son iguales se ejecuta la función done lanzando un error de tipo boom con un false.

Si todo es correcto se ejecuta done indicando que no hay error (null) y enviando el usuario (user).

Por defecto, la estrategia local maneja username y password, es posible cambiar esos valores por email y password mandando esas opciones antes de la función asíncrona con el uso de usernameField y passwordField.

const { Strategy } = require('passport-local');
const bcrypt = require('bcrypt');
const boom = require('@hapi/boom');

const UserService = require('../../../services/user.service');
const service = new UserService();

const LocalStrategy = new Strategy(
  {
    usernameField: 'email',
    passwordField: 'password',
  },
  async (email, password, done) => {
    try {
      const user = await service.findByEmail(email);
      if (!user) {
        done(boom.unauthorized(), false);
      }

      const isMatch = await bcrypt.compare(password, user.password);
      if (!isMatch) {
        done(boom.unauthorized(), false);
      }
      delete user.dataValues.password;
      done(null, user);
    } catch (error) {
      done(error, false);
    }
  }
);

module.exports = LocalStrategy;

En el archivo utils/auth/index.js se definen las estrategias a usar, cabe mencionar que puede tener muchas estrategias de autenticación. Algo muy importante es que debe implementarse en el index.js del proyecto con require('./utils/auth'):

const passport = require('passport');
const LocalStrategy = require('./strategies/local.strategy');

passport.use(LocalStrategy);

En user.service.js se hacen las modificaciones permanentes, en este caso se crea el método findByEmail para buscar por el email que es nuestro username.

async findByEmail(email) {
    const rta = await models.User.findOne({
      where: { email },
    });
    return rta;
  }

Para implementar la estrategia se crea un nuevo routing auth.router.js, cada estrategia tiene un nombre clave y debido a que funciona como un middleware, se necesita dejarlo pasar a la lógica de servicio o conectarlo a un servicio principal, pero antes hacer la validación.

En este caso se usa passport y con el método authenticate se indica cuál estrategia se va a autenticar diciéndole que no se desea manejar sesiones (session: false) ya que posteriormente se implementará JWT para manejar sesiones.

Si todo bien, entonces en el siguiente middleware se le envía un request con el usuario (req.user).

const express = require('express');
const passport = require('passport');

const router = express.Router();

router.post(
  '/login',
  passport.authenticate('local', { session: false }),
  async (req, res, next) => {
    try {
      res.json(req.user);
    } catch (error) {
      next(error);
    }
  }
);

module.exports = router;

Se implementa el nuevo router en routes/index.js:

const express = require('express');

const productsRouter = require('./api/products.route');
const usersRouter = require('./api/users.router');
const categoriesRouter = require('./api/categories.route');
const orderRouter = require('./api/orders.router');
const customerRouter = require('./api/customer.route');
const authRouter = require('./api/auth.route');

function routerApi(app) {
  const router = express.Router();
  app.use('/api', router);
  router.use('/products', productsRouter);
  router.use('/users', usersRouter);
  router.use('/categories', categoriesRouter);
  router.use('/orders', orderRouter);
  router.use('/customers', customerRouter);
  router.use('/auth', authRouter);
}

module.exports = routerApi;

Passport js summary:

  • Install:

    npm install passport

    You may install all strategies as you want, some of the available strategies are:

    passport-local

    passport-facebook

    passport-twitter

    **passport-jwt**

  • Configure environment:

    Following a good fold structure, we can follow the next structure

    • utils/
      index.js

      • auth/
        • strategies
    • Utils will contain all utilities in our program, one of these is Authentication tools

    • Inside auth, strategies stores all strategies that will be used in our application.

    • Finally to configure our strategies, create anindex.js file.

  • Programming strategies:

    • Step 1: Config Strategy

      Each strategy, have its own way to be programmed, in this case, local strategy is configured:

      //Destructure passport-local strategy and get just Strategy
      const { Strategy } = require('passport-local');
      //Import service which will be used for authentication
      const Service = require("./../../../services/user.service.js")
      const userService = new Service();
      const boom = require('@hapi/boom');
      const bcrypt = require('bcrypt');
      //Create a new strategy and configure it
      const localStrategy = new Strategy({
              usernameField: 'email'
          },
          async(email, password, done) => {
              try {
                  const user = await userService.findByMail(email);
      
                  if (!user) {
                      //return error and it wont be authenticated
                      done(boom.unauthorized(), false);
                      return;
                  }
                  //Using bcrypt to compare the password with the hash
                  const isMatch = await bcrypt.compare(password, user.password);
                  if (!isMatch) {
                      done(boom.unauthorized(), isMatch);
                      return;
                  }
                  delete user.dataValues.password;
                  //Null errors and return user
                  done(null, user);
              } catch (err) {
                  //Return error and false, it wont be authenticated
                  done(err, false);
              }
          });
      
      //Export the strategy
      module.exports = localStrategy;
      
    • Step 2: Config index.js

      Just need to configure in this way all strategies which will be used in our application

      //Require passport
      const passport = require('passport');
      //Require strategy used
      const localStrategy = require('./strategies/local.strategy');
      //Tell to passport we'll use localStrategy 
      passport.use(localStrategy);
      
    • Step 3: Config a route: routes/auth.router.js

      const express = require('express');
      
      const passport = require('passport');
      const router = express.Router();
      
      router.post('/login',
          //We are using the local strategy and not using sessions
          passport.authenticate('local', { session: false }),
          async(req, res, next) => {
              try {
                  res.json(req.user);
              } catch (err) {
                  next(err);
              }
          }
      );
      
      module.exports = router;
      
    • Step 4: Make our application work with passport

      In file index.js of root applications, just configure passport before initializing routes.

      const passport = require('passport');
      app.use(passport.initialize({ session: false }));
      
      • Final index.js example

        /*Server basics*/
        const express = require('express');
        const routerApi = require('./routes');
        /*Middlewares*/
        const { logErrors, errorHandler, boomErrorHandler, queryErrorHandler } = require('./middlewares/error.handler');
        const checkApiKey = require('./middlewares/auth.handler');
        const app = express();
        const port = process.env.PORT || 3000;
        const passport = require('passport');
        app.use(passport.initialize({ session: false }));
        
        app.use(express.json());
        
        app.get('/', checkApiKey, (req, res) => {
            res.send('<h1 style="text-align: center;font-family: Roboto sans-serif;">Hello Everybody (:</h1>');
        });
        /*Routes config*/
        
        routerApi(app);
        
        require("./utils/auth");
        /*Middlewares Config */
        app.use(logErrors);
        app.use(boomErrorHandler);
        app.use(errorHandler);
        app.use(queryErrorHandler);
        /*Serve*/
        app.listen(port, () => {
            // eslint-disable-next-line no-console
            console.log(`Server running in port ${port}`);
        });
        

🌉 Clase #7: Implementando login con Passport.js 7/20 🌉

 

¿Qué es Passport js? 🚣

 
Passport contiene una serie de librerías y estrategias (más de 500 estrategias) que permite hacer la capa de autenticación. (Fuente: aquí).
 

¿Qué significa que Passport sea versátil? ⛵️

 
Passport permite logearnos mediante diferentes estrategias o formas como Twitter, Google, Facebook, etc. Lo que se hace es teniendo nuestro código base, aplicamos con Passport la estrategia con la que queremos hacer login a través del endpoint /auth/login.
 

 

  • Vamos a instalar la primera estrategia: passport-local que es la estrategia más básica que permite logearnos con nuestro usuario y contraseña.
     
  • Para instalar passport y passport-local vamos a la terminal y ejecutamos:
     
npm i passport passport-local

 

  • Ahora vamos a VSC para implementar la estrategia, creamos la carpeta utils, dentro de utils, se crea otra carpeta llamada auth, dentro de auth, creamos el archivo index.js, el código queda:
     
const passport = require('passport');
//Aqui se definen qué estrategias se van a usar
const LocalStrategy = require('./strategies/local.strategy');

passport.use(LocalStrategy);

 
Guardamos, dentro de la carpeta de auth, se crea la carpeta donde estarán todas las estrategias: strategies, dentro de strategies, creamos el archivo local.strategy.js donde se implementará la lógica del passport-local, el código queda:
 

//Nos treamos a passport-local
const { Strategy } = require('passport-local');
//Usamos a boom como manejador de errores
const boom = require('@hapi/boom');
const bcrypt = require('bcrypt');

const UserService = require('../../../services/user.service');
//Se crea una instancia de servicio
const service = new UserService();

//Constructor
const LocalStrategy = new Strategy({
	//La estrategia local es la más básica
	usernameField: 'email',
	passwordField: 'password'
	},
	async (email, password, done) => {
		try {
			//Buscar con findByEmail el usuario
			const user = await service.findByEmail(email);
			//Validaión para cuando el usuario no exista
			if (!user) {
				//Así se envían los errores con false
				done(boom.unauthorized(), false);
			}
			//Comprobación del password con el hash
			const isMatch = await bcrypt.compare(password, user.password);
			//Si el password no coincide, sale un mensaje que el usuario no está autorizado
			if (!isMatch) {
				done(boom.unauthorized(), false);
			}
			delete user.dataValues.password;
			//Si todo salió bien, se ejecuta el done enviando null diciendo que nno hay error
			done(null, user);
		} catch (error) {
			done(error, false);
		}
	}
);
module.exports = LocalStrategy;

 
Guardamos, vamos a la carpeta de services y abrimos el archivo de user.services.js, después de la función find(), se implementa la función findByEmail(email) que permitirá buscar el usuario por el email, el código queda:
 

//Encontrar el primer usuario que tenga el email qué además es único
async findByEmail(email) {
	const rta = await models.User.findOne({
		where: { email }
	});
	return rta;
}

 
Guardamos, vamos a la carpeta routes, creamos el archivo auth.router.js, el código queda:
 

const express = require('express');
const passport = require('passport');
//No se necesita validar con el schema
//const validatorHandler = require('./../middlewares/validator.handler');
//const { loginAuthSchema } = require('./../schemas/user.schema');

const router = express.Router();

//Funciona como un middleware
router.post('/login',
  passport.authenticate('local', {session: false}),
  async (req, res, next) => {
    try {
      //Pasa el usuario
      res.json(req.user);
    } catch (error) {
      next(error);
    }
  }
);

/*router.post(
  "/login",
  validatorHandler(loginAuthSchema, "body"),
  passport.authenticate("local", { session: false }),
  async (req, res, next) => {
    try {
      res.json(req.user);
    } catch (err) {
      next(err);
    }
  }
);*/

module.exports = router;

 
Guardamos, abrimos dentro de la carpeta routes el archivo index.js, agregamos donde están las constantes al final de éstas:
 

const authRouter = require('./auth.router');

 
También agregamos la ruta dentro de routerApi():
 

router.use('/auth', authRouter);

 
Guardamos, abrimos el archivo de index.js (el index más externo) y agregamos un require dinámico para que entienda donde se debe dirigir cuando se haga el endpoint:
 

//require de forma dinámica para ejecutar el archivo de la estrategia
require('./utils/auth');

 
Guardamos, si no está corriendo en la terminal en modo de desarrollador, se ejecuta: npm run dev
 

  • Vamos a Insomnia, creamos una carpeta llamada Auth, dentro creamos la petición POST llamada Login, en la dirección se coloca: .API_URL/api/v1/auth/login, en el body del JSON, colocamos:
     
{
	"email": "[email protected]",
	"password": "12356 .2020",
	"role": "admin"
}

 
En la salida debe salir el código 200 OK (esto significa que nuestra solicitud de logear con ese email y contraseña son correctos):
 

{
	"id": 3,
	"email": "[email protected]",
	"role": "admin",
	"createdAt": "2023-03-17T02:47:32.524Z"
}

 
En caso de ingresar un email que no sea correcto la salida se tiene un código 401 Unauthorized:
 

{
	"statusCode": 401,
	"error": "Unauthorized",
	"message": "Unauthorized"
}

 
Nota: Si se quiere editar los nombres de los campos de entrada para el Login, en el archivo local.strategy.js de la ruta: utils/auth/strategies se debe indicar los nombres autorizados:
 

usernameField: 'email',
passwordField: 'password'

 

Por si a alguien le pasa lo mismo que a mi , por mas que pusiera “app.use(passport.initialize());” en el index me seguia dando el error de que la funcion authenticate no existia y que si o si tenia que nombrar la estrategia, la unica solucion que me funciono fue declarar la new strategy en el mismo index de la carpeta auth mi codigo quedo asi:

const boom = require('@hapi/boom');
const bcrypt = require('bcrypt');
const passport = require('passport')
const LocalStrategy = require('passport-local').Strategy;
const UserService = require('../../services/user.service')
const service = new UserService()

passport.use(new LocalStrategy({
  usernameField: 'email',
  passwordField: 'password'
}, async (email, password, done) => {
  try {
    const user = await service.findByEmail(email)
    if(!user){
      done(boom.unauthorized(), false)
    }
    const isMatch = await bcrypt.compare(password, user.password)
    if(!isMatch){
      done(boom.unauthorized(), false)
    }
    delete user.dataValues.password
    done(null, user)
  } catch (error) {
    done(error, false)
  }
}))

Hay un problema con la version de passport. Si utilizan la misma version que en el curso, la 0.4.1, todo sale bien. Si utilizan la ultima version, la 0.5.0, van a tener el error TypeError: req.logIn is not a function, por lo que hay que reescribir la estrategia. Yo decidi dejarla como en el curso y utilizar la version 0.4.1, despues la actualizo

Aqui les dejo un aporte de como implementar el login con username o con el correo.

En LocalStrategy

const LocalStrategy = new Strategy(
  {
    usernameField: 'identifier',
    passwordField: 'password',
  },
  async (identifier, password, done) => {
    try {
      const user = await service.userLogin(identifier);
      if (!user) {
        const user = await service.emailLogin(identifier);
        if (!user) {
          done(boom.unauthorized('User not found'));
        } else {
          const validatePassword = await bcrypt.compare(password, user.user.password);
          if (!validatePassword) {
            done(boom.unauthorized('Invalid Password'), false);
          } else {
            delete user.user.dataValues.password;
            done(null, user);
          }
        }
      } else {
        const validatePassword = await bcrypt.compare(password, user.password);
        if (!validatePassword) {
          done(boom.unauthorized('Invalid Password'), false);
        } else {
           delete user.dataValues.password;
           done(null, user);
          }
        }
    } catch (error) {
      done(error, false);
    }
  },
);

En el service de users cree dos metodos para buscar por username o por correo

async userLogin(username) {
    const user = await models.User.findOne({where: { username }, include: ['customer']});
      return user;
  }

  async emailLogin (email) {
    const customer = await models.Customer.findOne({where: { email }, include: ['user']});
    return customer;
  }

Debo mencionar que las relaciones entre user y customer lo manejo diferente al profe

Me arroja “Bad Request”, no se como solucionarlo 😕

Para evitar que en cualquier consulta que involucre los usuarios puede indicar un getter en modelo User en el campo password que retorne siempre nulo este valor…

  password: {
    allowNull: false,
    type: DataTypes.STRING,
    get() {
      return null;
    },
  },

En lo personal elijo mantener el esquema de validación.
Lo coloque antes de la authenticacion, ya que, si hay un error con los datos enviados, passport solo nos lanzara un “Bad request”, en cambio con el esquema podemos mostrar cuales son los datos que no están siendo enviados correctamente en el “body” de la petición.

router.post(
  "/login",
  handleValidator(loginAuthSchema, "body"),
  passport.authenticate("local", { session: false }),
  async (req, res, next) => {
    try {
      res.json(req.user);
    } catch (err) {
      next(err);
    }
  }
);

Con esquema:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "\"password\" is required"
}

Sin esquema:

Bad Request
npm i passport passport-local
Si les aparece el siguiente error: `TypeError: Cannot read properties of undefined (reading 'name')` Eliminado los corchetes, dejando el import de la siguiente manera `const localStrategy = require('./strategies/local.strategy');` Se corrige
**¿Qué es Passport?** Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : ````npm //Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local ```` **Para empezarlo a usar** ````js // Nos traemos el módulo passport-local que es un objeto con diferentes propiedades a usar. // Utilizamos la desestructuración para obtener únicamente la propiedad {Strategy} del módulo passport-local. const {Strategy} = require("passport-local") // Ahora creamos una instancia de strategy dado que es un constructor const localStrategy = new Strategy() // Exportamos la variable instanciada module.exports = localStrategy ```` Ahora podemos empezar a usar el local passport ```js // Para usar la instancia tenemos 3 parámetros username, password , done donde "done" funcionara para las respuestas correctas y para los errores // "A través de done(), proporcionamos los siguientes parámetros: `done(error, user, info)`. Primero, el parámetro 'error' se establece en `null` si la autenticación fue exitosa o se pasa el error específico en caso de fallo. Para el parámetro 'user', se proporciona `false` si la autenticación falla, indicando que no se encontró el usuario, o se envía la información del usuario si la autenticación es correcta. El parámetro opcional 'info' se utiliza para incluir detalles adicionales, como mensajes de error específicos, como 'nombre de usuario incorrecto'." const localStrategy = new Strategy(async(email, password, done)=>{ try {       const user= service.findByEmail(email) // Digamos que falla la verificación le pasamos el error en este caso no autorizado y le decimos que la validación fallo       if(!user){         done(boom.unauthorized() , false)       } // Si salio todo bien debemos devolver null y el usuario en cuestión       done(null, user)   } catch (error) {     done(error,false)   } }) ```` Listo sabiendo lo anterior si queremos usarlo podemos utilizar la siguiente lógica ````js // Traemos a todo el modulo de passport const passport = require("passport") // Traemos la instacia de estrategia previamente hecha const loca\_strategy = require("./strategies/loca\_strategy") // Le decimos a passport la estrategia a usar la ventaja de trabajar de este modo es que si quisiéramos usar otras estrategias simplemente le tendriamos que pasar la instacia a passport.use() y funcionaria passport.use(loca\_strategy) ````
\## ¿Qué es Passport? Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : ````npm //Para hacer uso de cualquier estrategia de passport debemos instalar Passport y seguido de la estrategia que queramos usar npm i passport passport-local ```` **Para empezarlo a usar** ````js // Nos traemos el módulo passport-local que es un objeto con diferentes propiedades a usar. // Utilizamos la desestructuración para obtener únicamente la propiedad {Strategy} del módulo passport-local. const {Strategy} = require("passport-local") // Ahora creamos una instancia de strategy dado que es un contructor const localStrategy = new Strategy() // Exportamos la varible instaciada module.exports = localStrategy ````
**¿Qué es Passport?** Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : ````npm //Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local ````
**¿Qué es Passport?** Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : ```js //Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local ```Para empezarlo a usar ```js // Nos traemos el módulo passport-local que es un objeto con diferentes propiedades a usar. // Utilizamos la desestructuración para obtener únicamente la propiedad {Strategy} del módulo passport-local. const {Strategy} = require("passport-local") // Ahora creamos una instancia de strategy dado que es un contructor const localStrategy = new Strategy() // Exportamos la varible instaciada module.exports = localStrategy ```
**¿Qué es Passport?** Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : ```js //Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local ```
**¿Qué es Passport?** Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : `//Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar ` `npm i passport passport-local`
**¿Qué es Passport?** Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : `````js ```` //Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local ```` `````````npm //Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local ````
**¿Qué es Passport?** Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. Para instalarlo : ```js //Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local ```//Para hacer uso de cualquier estrategia de passport debemos instalar passport y seguido de la estrategia que queramos usar npm i passport passport-local
\## ¿Qué es Passport? Passport es una librería que proporciona un conjunto de estrategias para la autenticación. Aunque podríamos crear nuestros propios métodos de inicio de sesión, Passport ofrece múltiples maneras de hacerlo, permitiéndonos usar autenticaciones a través de GitHub, Google, LinkedIn, y métodos locales, entre otros. En este caso, vamos a usar la estrategia local de Passport, que funciona con el tradicional nombre de usuario y contraseña. **Para instalarlo** : ```js npm i passport passport-local ```**Para inicializarlo a usar** ```js // Nos traemos el módulo passport-local que es un objeto con diferentes propiedades a usar. // Utilizamos la desestructuración para obtener únicamente la propiedad {Strategy} del módulo passport-local. const {Strategy} = require("passport-local") // Ahora creamos una instancia de strategy dado que es un contructor const localStrategy = new Strategy() // Exportamos la varible instaciada module.exports = localStrategy ```**Para empezar usar Passport local** ````js // Para usar la instancia tenemos 3 parametros username, password , done donde "done" funcionara para las respuestas correctas y para los errores // "A través de done(), proporcionamos los siguientes parámetros: `done(error, user, info)`. Primero, el parámetro 'error' se establece en `null` si la autenticación fue exitosa o se pasa el error específico en caso de fallo. Para el parámetro 'user', se proporciona `false` si la //autenticación falla, indicando que no se encontró el usuario, o se envía la información del usuario si la autenticación es correcta. El parámetro opcional //'info' se utiliza para incluir detalles adicionales, como mensajes de error específicos, como 'nombre de usuario incorrecto'." const localStrategy = new Strategy(async(email, password, done)=>{ try {       const user= service.findByEmail(email) // Digamos que falla la verificacion le pasamos el error en este caso no autorizado y le decimos que la validacion fallo       if(!user){         done(boom.unauthorized() , false)       } // Si salio todo bien debemos devolver null y el usuario en cuestion       done(null, user)   } catch (error) {     done(error,false)   } }) ``` ```` Listo sabiendo lo anterior si queremos usarlo podemos utilizar la siguiente lógica ```js // Traemos a todo el modulo de passport const passport = require("passport") // Traemos la instacia de estrategia previamente hecha const loca_strategy = require("./strategies/loca_strategy") // Le decimos a passport la estrategia a usar la ventaja de trabajar de este modo es que si quisieramos usar otras estrategias simplemente le tendriamos que pasar la instacia a passport.use() y funcionaria passport.use(loca_strategy) ```
me encanta todos los cursos y me gusta mucho que Nico dice POTENTE!! me siento POTENTE!
*Es un conjunto de **librerías** y **estrategias** que permiten **realizar** la **capa** de **autenticación**.* **Passport.js** *es **bastante** **importante** y **versátil**, ya que permite **generar varias estrategias**, con un **código** **base** para que los **usuarios** **inicien** **sección** de **varias** **maneras**.*

Afortunadamente no me aparecieron errores, adicionalmente le agregue mensajes para cuando el usuario se equivoque con su email o con su contraseña

if (!user)
  done(
    boom.unauthorized(
      "The provided email address is not associated with any account."
    ),
    false
);

const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch)
  done(
    boom.unauthorized(
      "The provided password is incorrect. Please try again."
    ),
    false
);

Si alguien esta teniendo el error “Authentication strategies must have a name” en la última versión de passport ( “passport”: “^0.6.0”, “passport-local”: “^1.0.0”). Lo pueden solucionar así:

El archivo local.strategy.js lo tienen que modificar así:

const { Strategy } = require("passport-local");
const boom = require("@hapi/boom");
const UserService = require("../../../services/users.service");
const AuthService = require("../../../services/auth.service");

const userSvc = new UserService();
const authSvc = new AuthService();

const localStrategyHandler = async (email, password, done) => {
  try {
    const user = await userSvc.getByEmail(email);
    if (!user) return done(boom.notFound(), false);

    const isMatch = await authSvc.verify(password, user.password);
    if (!isMatch) return done(boom.unauthorized(), false);

    return done(null, user);
  } catch (error) {
    return done(error, false);
  }
};

// Asignamos un nombre a la estrategia: "local"
const LocalStrategy = new Strategy({ usernameField: 'email', name: "local" }, localStrategyHandler);

module.exports = LocalStrategy;

El utils/auth/index.js deben modificarlo para exportar el módulo así:

const passport = require("passport");
const LocalStrategy = require("./strategies/local.strategy");

passport.initialize();
passport.use("local", LocalStrategy);

module.exports = passport;

Finalmente, en el index.js principal (el que está en la carpeta raíz) deben importar passport desde el modulo anterior e inicializarlo, así:

//En las importanciones
const express = require("express");
const app = express();
const passport = require("./utils/auth"); // Así lo importamos

// Resto de código

app.use(express.json());
const whitelist = ['url'];
const options = {
  origin: (origin, callback) => {
    if (whitelist.includes(origin) || !origin) {
      callback(null, true);
    } else {
      callback(new Error('no permitido'));
    }
  }
}
app.use(cors(options));
app.use(passport.initialize()); // Así lo inicializamos

// Resto de código

Con eso ya el error se soluciona

Recuerden que para tener mejores mensajes de error, podemos agregar un argumento a boom:

if (!user) {
	done(boom.unauthorized("Sorry, this email does not exist."), false); // email no existe
  }

const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
	done(boom.unauthorized("Ups! Wrong password."), false); // contraseña incorrecta
}

para los que les salga este error:
.
=> Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client

es por que no estan retornando la funcion del callback de done y el servidor trata de enviar ma´s de una respuesta, esto pasa porue se sigue ejecuntando las lineas despuésde mandar el error de esta manera
.

done(boom.unauthorized(), false);

solucion: retornar la funcion cb done
=>

  • return done(boom.unauthorized(), false);