# 4.- Autenticación
Ahora realizaremos la autenticación de usuarios:
# Models
Crearemos nuestro modelo utilizando campos únicos, en la carpeta models
crea un archivo user.js
import mongoose from 'mongoose';
const uniqueValidator = require('mongoose-unique-validator');
// Roles
const roles = {
values: ['ADMIN', 'USER'],
message: '{VALUE} no es un rol válido'
}
const Schema = mongoose.Schema;
const userSchema = new Schema({
nombre: { type: String, required: [true, 'El nombre es necesario'] },
email: { type: String, unique: true, required: [true, 'Email es necesario'] },
pass: { type: String, required: [true, 'Pass es necesario'] },
date: { type: Date, default: Date.now },
role: { type: String, default: 'USER', enum: roles },
activo: { type: Boolean, default: true }
});
// Validator
userSchema.plugin(uniqueValidator, { message: 'Error, esperaba {PATH} único.' });
// Convertir a modelo
const User = mongoose.model('User', userSchema);
export default User;
# bcrypt
Vamos a encriptar la contraseña https://www.npmjs.com/package/bcrypt (opens new window)
npm i bcrypt --save
En nuestra ruta users.js
var express = require('express');
var router = express.Router();
// Importamos modelo Tarea
import User from '../models/user';
// Hash Contraseña
const bcrypt = require('bcrypt');
const saltRounds = 10;
router.post('/nuevo-usuario', async (req, res) => {
const body = {
nombre: req.body.nombre,
email: req.body.email,
role: req.body.role
}
body.pass = bcrypt.hashSync(req.body.pass, saltRounds);
try {
const userDB = await User.create(body);
return res.json(userDB);
} catch (error) {
return res.status(500).json({
mensaje: 'Ocurrio un error',
error
});
}
});
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
# Eliminar pass JSON
En nuestro Squema agregar: info (opens new window)
// Eliminar pass de respuesta JSON
userSchema.methods.toJSON = function() {
var obj = this.toObject();
delete obj.pass;
return obj;
}
# PUT
router.put('/usuario/:id', async(req, res) => {
let id = req.params.id;
let body = req.body;
try {
// {new:true} nos devuelve el usuario actualizado
const usuarioDB = await User.findByIdAndUpdate(id, body, {new: true});
return res.json(usuarioDB);
} catch (error) {
return res.status(400).json({
mensaje: 'Ocurrio un error',
error
})
}
});
# runValidators: true
Agregaremos otra opción a nuestra actualización para que corra las validaciones (para que no se puedan ingresar roles inválidos)
const usuarioDB = await User.findByIdAndUpdate(id, body, {new: true, runValidators: true});
# Underscore
https://underscorejs.org/ (opens new window) nos permitirá agregar validaciones
Instalación:
npm install underscore --save
Agregar a la ruta:
// Filtrar campos de PUT
const _ = require('underscore');
utilizar para filtrar
router.put('/usuario/:id', async(req, res) => {
let id = req.params.id;
let body = _.pick(req.body, ['nombre', 'email', 'role', 'pass']);
if(body.pass){
body.pass = bcrypt.hashSync(req.body.pass, saltRounds);
}
try {
// {new:true} nos devuelve el usuario actualizado
const usuarioDB = await User.findByIdAndUpdate(id, body, {new: true, runValidators: true});
return res.json(usuarioDB);
} catch (error) {
return res.status(400).json({
mensaje: 'Ocurrio un error',
error
})
}
});
# DELETE Usuario
router.delete('/usuario/:id', async(req, res) => {
let id = req.params.id;
try {
const usuarioDelete = await User.findByIdAndRemove(id);
if(!usuarioDelete){
return res.status(400).json({
mensaje: 'Usuario no encontrado'
})
}
return res.json(usuarioDelete);
} catch (error) {
return res.status(400).json({
mensaje: 'Ocurrio un error',
error
})
}
});
# Ruta Login
Crear una nueva ruta: login.js
const express = require('express');
const router = express.Router();
import User from '../models/user';
const bcrypt = require('bcrypt');
const saltRounds = 10;
router.get('/', async(req, res) => {
res.json({mensaje: 'Funciona!'})
})
module.exports = router;
Configurar app.js
// Usamos las rutas
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/login', require('./routes/login'));
# POST login
router.post('/', async(req, res) => {
let body = req.body;
try {
// Buscamos email en DB
const usuarioDB = await User.findOne({email: body.email});
// Evaluamos si existe el usuario en DB
if(!usuarioDB){
return res.status(400).json({
mensaje: 'Usuario! o contraseña inválidos',
});
}
// Evaluamos la contraseña correcta
if( !bcrypt.compareSync(body.pass, usuarioDB.pass) ){
return res.status(400).json({
mensaje: 'Usuario o contraseña! inválidos',
});
}
// Pasó las validaciones
return res.json({
usuarioDB,
token: 'fkajsdkf'
})
} catch (error) {
return res.status(400).json({
mensaje: 'Ocurrio un error',
error
});
}
});
# JWT
https://jwt.io/ (opens new window)
Instalación https://www.npmjs.com/package/jsonwebtoken (opens new window)
npm i jsonwebtoken --save
Importamos la librería:
// JWT
const jwt = require('jsonwebtoken');
Utilizamos JWT
// Evaluamos la contraseña correcta
if( !bcrypt.compareSync(body.pass, usuarioDB.pass) ){
return res.status(400).json({
mensaje: 'Usuario o contraseña! inválidos',
});
}
// Generar Token
let token = jwt.sign({
data: usuarioDB
}, 'secret', { expiresIn: 60 * 60 * 24 * 30}) // Expira en 30 días
// Pasó las validaciones
return res.json({
usuarioDB,
token: token
})
# Middlewares
Crear carpeta en la raíz de nuestro proyecto llamada middlewares
y dentro un archivo llamado: autenticacion.js
const verificarAuth = (req, res, next) => {
// Leer headers
let token = req.get('token');
console.log(token);
next();
}
module.exports = {verificarAuth};
Ahora en la ruta de user.js
llamamos al middleware para ver si está funcionando...
const {verificarAuth} = require('../middlewares/autenticacion.js');
router.get('/usuario', verificarAuth , async(req, res) => {
# Verificar Token
Vamos a verificar un token válido, en autenticacion.js
(Al enviar la petición get a través de Postman envíar en los header un token válido de login);
const jwt = require('jsonwebtoken');
let verificarAuth = (req, res, next) => {
// Leer headers
let token = req.get('token');
jwt.verify(token, 'secret', (err, decoded) => {
if(err) {
return res.status(401).json({
mensaje: 'Error de token',
err
})
}
// Creamos una nueva propiedad con la info del usuario
req.usuario = decoded.data; //data viene al generar el token en login.js
next();
});
}
module.exports = {verificarAuth};
Ahora aplicar a todas la peticiones de user.
# Verificar rol ADMIN
let verificaRol = (req, res, next) => {
let rol = req.usuario.role;
console.log(rol);
if(rol !== 'ADMIN'){
return res.status(401).json({
mensaje: 'Rol no autorizado!'
})
}
next();
}
module.exports = {verificarAuth, verificaRol};
Utilizar en POST, PUT, DELETE
// Middlewares
const {verificarAuth, verificaRol} = require('../middlewares/autenticacion');
router.post('/nuevo-usuario', [verificarAuth, verificaRol], async (req, res) => {
router.put('/usuario/:id', [verificarAuth, verificaRol], async(req, res) => {
router.delete('/usuario/:id', [verificarAuth, verificaRol], async(req, res) => {
# Middleware a Notas
import express from 'express';
const router = express.Router();
// importar el modelo nota
import Nota from '../models/nota';
const {verificarAuth, verificarAdministrador} = require('../middlewares/autenticacion')
// Agregar una nota
router.post('/nueva-nota',verificarAuth, async(req, res) => {
const body = req.body;
body.usuarioId = req.usuario._id;
try {
const notaDB = await Nota.create(body);
res.status(200).json(notaDB);
} catch (error) {
return res.status(500).json({
mensaje: 'Ocurrio un error',
error
})
}
});
// Get con todos los documentos
router.get('/nota',verificarAuth, async(req, res) => {
const usuarioId = req.usuario._id
try {
const notaDb = await Nota.find({usuarioId});
res.json(notaDb);
} catch (error) {
return res.status(400).json({
mensaje: 'Ocurrio un error',
error
})
}
});
// Exportación de router
module.exports = router;