No tienes acceso a esta clase

隆Contin煤a aprendiendo! 脷nete y comienza a potenciar tu carrera

Implementando el env铆o de emails

16/20
Recursos

Aportes 8

Preguntas 2

Ordenar por:

驴Quieres ver m谩s aportes, preguntas y respuestas de la comunidad?

o inicia sesi贸n.

Estoy as铆 con este curso 馃く馃く馃く馃く

Debido a que hay mucha l贸gica regada sobre autenticaci贸n, se crea un nuevo servicio para auth y hacer esto m谩s mantenible.

auth.service.js, el m茅todo getUser contiene la l贸gica para autenticar un usuario, signToken contiene la l贸gica para firmar un token y sendMail contiene la l贸gica para enviar un email con sus respectectivas variables de ambiente:

const boom = require('@hapi/boom');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const nodemailer = require('nodemailer');

const { config } = require('../config/config');

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

class AuthService {
  async getUser(email, password) {
    const user = await service.findByEmail(email);
    if (!user) {
      throw boom.unauthorized();
    }

    const isMatch = await bcrypt.compare(password, user.password);
    if (!isMatch) {
      throw boom.unauthorized();
    }
    delete user.dataValues.password;
    return user;
  }

  signToken(user) {
    const payload = {
      sub: user.id,
      role: user.role,
    };
    const token = jwt.sign(payload, config.jwtSecret);
    return {
      user,
      token,
    };
  }

  async sendMail(email) {
    const user = await service.findByEmail(email);
    if (!user) {
      throw boom.unauthorized();
    }

    const transporter = nodemailer.createTransport({
      host: 'smtp.gmail.com',
      secure: true, // true for 465, false for other ports
      port: 465,
      auth: {
        user: config.mailerEmail,
        pass: config.mailerPassword,
      },
    });

    await transporter.sendMail({
      from: `"Foo Boo 馃懟" <${config.mailerEmail}>`, // sender address
      to: `${user.email}`, // list of receivers
      subject: 'Nuevo correo de prueba', // Subject line
      text: 'Estoy usando Nodemailer!', // plain text body
      html: '<b>Holaaaaaaaaaa!</b>', // html body
    });

    return { message: 'Mail sent' };
  }
}

module.exports = AuthService;

Se hacen las modificaciones pertinentes en los archivos auth.route.js y local.strategy.js donde se hace el uso del nuevo servicio.

auth.route.js, en el caso del endpoint /recovery, se obtiene el email del body, posteriormente se ejecuta el m茅todo sendMail que viene desde el servicio:

const express = require('express');
const passport = require('passport');
const AuthService = require('../../services/auth.service');

const router = express.Router();
const service = new AuthService();

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

router.post('/recovery', async (req, res, next) => {
  try {
    const { email } = req.body;
    const rta = await service.sendMail(email);
    res.json(rta);
  } catch (error) {
    next(error);
  }
});

module.exports = router;

local.strategy.js, el m茅todo getUser contiene la l贸gica antes establecida en este archivo para autenticar un usuario:

const { Strategy } = require('passport-local');

const AuthService = require('../../../services/auth.service');
const service = new AuthService();

const LocalStrategy = new Strategy(
  {
    usernameField: 'email',
    passwordField: 'password',
  },
  async (email, password, done) => {
    try {
      const user = await service.getUser(email, password);
      done(null, user);
    } catch (error) {
      done(error, false);
    }
  }
);

module.exports = LocalStrategy;

El curso esta muy bien explicado y haberlo dividido en 3 o4 partes fue una gran idea

esta clase va a mil por hora jaja

Excelente introduccion al envio de correos con node, en mi trabajo hemos tenido bastantes inconvenientes con correos que llegan a spam, ya sea por la estructura del html, o el dominio es distintos del from al servicio que los envia, etc.
Existen spam tester en linea que les ayudan a identificar las vulnerabilidades de sus correos 馃槈

Urgente el boton de like!!!

Soluci贸n RETO de correo y contrase帽a en variables de entorno:
.env

# Agregamos estas 2 l铆neas
EMAIL_SENDER[email protected]
EMAIL_PASSWORD=password

config.js

# Agregamos estas 2 l铆neas
emailSender: process.env.EMAIL_SENDER,
emailPassword: process.env.EMAIL_PASSWORD

Y finalmente en auth.service.js

# Modificamos esta parte
auth: {
     user: config.emailSender,
     pass: config.emailPassword
}

Saludos.

馃浌 Clase #16: Implementando el env铆o de emails 16/20 馃浌



Pasos: 馃摑

  • Vamos a VSC, luego a la carpeta services, creamos un archivo llamado auth.service.js, se implementar谩 la l贸gica del getUser que contendr谩 la implementaci贸n de la instancia service de local.strategy.js, adem谩s de la l贸gica de signToken y de sendEmail, el c贸digo queda as铆:
//Importar boom para los errores:
const boom = require('@hapi/boom');
//Importar bcrypt para comparar la contrase帽a:
const bcrypt = require('bcrypt');
//Importar jwt para la firma:
const jwt = require('jsonwebtoken');
//Importar nodemailer para el env铆o del email:
const nodemailer = require('nodemailer');
//Importar config para obtener el secret
const { config } = require('./../config/config');
//Importar el servicio de los usuarios
const UserService = require('./user.service');
const service = new UserService();

class AuthService {
	//Obtener un usuario en base de un email y un password:
	async getUser(email, password) {
		const user = await service.findByEmail(email);
		if (!user) { //Lanzamos el error cuando no est谩 autorizado el 				usuario:
			throw boom.unauthorized();
		}
		const isMatch = await bcrypt.compare(password, user.password);
		if (!isMatch) {
			throw boom.unauthorized();;
		}
		delete user.dataValues.password;
		//Se retorna el usaurio sin imprimir el password
		return user;
	}
	//Recibe el usuario que est谩 autenticado:
	signToken(user) {
		const payload = {
			sub: user.id,
			role: user.role
		}
		const token = jwt.sign(payload, config.jwtSecret);
		return {
			user,
			token
		};
	}

	async sendMail(email) {
		//Comprobar si en verdad est谩 en la base de datos:
		const user = await service.findByEmail(email);
		if (!user) {
			throw boom.unauthorized();
		}
		const transporter = nodemailer.createTransport({
			host: "smtp.gmail.com",
			secure: true, // true for 465, false for other ports
			port: 465,
			auth: {
				user: '[email protected]',
				pass: 'dmlikrjugujjlugl'
			}
		});
		await transporter.sendMail({
			from: '[email protected]', // sender address
			to: `${user.email}`, // list of receivers
			subject: "Este es un nuevo correo", // Subject line
			text: "Hola santi", // plain text body
			html: "<b>Hola santi</b>", // html body
		});
		//Retorna un mensaje:
		return { message: 'mail sent' };
	}
}

module.exports = AuthService;


Guardamos, vamos a la ruta utils/auth/strategies y abrimos el archivo local.strategy.js y editamos el c贸digo para implementar la llamada de service, el c贸digo queda:

//Nos treamos a passport-local
const { Strategy } = require('passport-local');

const AuthService = require('./../../../services/auth.service');
const service = new AuthService();

const LocalStrategy = new Strategy({
	usernameField: 'email',
	passwordField: 'password'
},
async (email, password, done) => {
	try {//sevice viene de authservice.js donde queda toda la l贸gica que teniamos antes
		const user = await service.getUser(email, password);
		done(null, user);
	} catch (error) {
		done(error, false);
	}
}
);

module.exports = LocalStrategy;


Guardamos, vamos a la carpeta routes, abrimos el archivo auth.router.js, vamos adaptar el router.post(/login ...), implementando las funciones de auth.service.js: signToken y sendEmail, tambi茅n se implementa la l贸gica de router.post(/recovery 鈥), el c贸digo queda:

const express = require('express');
const passport = require('passport');
//Importar a auth.service:
const AuthService = require('./../services/auth.service');

const router = express.Router();
//Crear la instancia de nuestro servicio
const service = new AuthService();

//Para recuperar
router.post('/login',
	passport.authenticate('local', {session: false}),
	async (req, res, next) => {
		try {
			const user = req.user;
			//Llamar a signToken (como es sincrono se puede resolver sin ning煤n await):
			res.json(service.signToken(user));
		} catch (error) {
			next(error);
		}
	}
);

//No tiene autenticaci贸n, solo pide el email del body para comprobarlo
router.post('/recovery',
	async (req, res, next) => {
		try {
			const { email } = req.body;
			//Llamar a sendMail (es asincrono):
			const rta = await service.sendMail(email);
			res.json(rta);
		} catch (error) {
			next(error);
		}
	}
);

module.exports = router;


Guardamos, es importante se帽alar que el correo y el password que est谩n en auth.service.js debe estar registrado en la base de datos.

Si no se ha corrido el sistema, ejecutar en la terminal: npm run dev y esperar a que salga My port 3000

  • Ir a Insomnia, dentro de la carpeta Auth se crea la petici贸n POST recovery, con la direcci贸n: {{ _.API_URL }}/api/v1/auth/recovery, en el body se coloca JSON y se coloca un correo:
{
	"email": "[email protected]"
}


Si el correo no est谩 registrado en la base de datos, sale un c贸digo 401 Unauthorized:

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


Si se verifica que si se encuentra registrado sale el c贸digo 200 OK:

{
	"message": "mail sent"
}

  • Podemos revisar la bandeja de entrada y debe estar el correo que configuramos.