Estoy así con este curso 🤯🤯🤯🤯
Introducción
Cómo autenticar usuarios con Node.js
Autenticación vs. autorización
Tienda en línea: instalación del proyecto
Protección de contraseñas
Middleware de verificación
Hashing de contraseñas con bcryptjs
Implementando hashing para usuarios
Passport y JSON Web Tokens
Implemetando login con Passport.js
¿Qué es un JWT?
Firmar y verificar tokens
Generar JWT en el servicio
Protección de rutas
Control de roles
Obteniendo órdenes del perfil
Manejo de la autenticación desde el cliente
Envío de emails con Node.js
Cómo enviar emails con Node.js
Implementando el envío de emails
Recuperación de contraseñas
Generando links de recuperación
Validando tokens para cambio de contraseña
Despliegue a producción
Deploy en Heroku
Próximos pasos
Cómo seguir aprendiendo backend con Node.js
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Aportes 10
Preguntas 2
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!!!
Pasos: 📝
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
{{ _.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"
}
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?