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 10

Preguntas 2

Ordenar por:

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

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

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 😉

esta clase va a mil por hora jaja

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.

Urgente el boton de like!!!

🛹 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.
     
Muy bueno este curso, he aprendido muchas cosas nuevas!
donde veo los recursos de la clase