Cómo utilizar Mongoose/Mongodb con node.js – autenticación de passport.
Estoy construyendo mi primera aplicación de pila completa node.js y quiero usar passport para la autenticación. Encontré un tutorial para passport que almacenaba la información de los usuarios en una matriz de usuarios.
Archivo passport-config.js:
const LocalStrategy = require('passport-local').Strategy
const bcrypt = require('bcrypt')
function initialize(passport, getUserByEmail, getUserById) {
const authenticateUser = async (email, password, done) => {
const user = getUserByEmail(email)
if (user == null) {
return done(null, false, { message: 'No hay ningún usuario con ese correo electrónico' })
}
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user)
} else {
return done(null, false, { message: 'Contraseña incorrecta' })
}
} catch (e) {
return done(e)
}
}
passport.use(new LocalStrategy({ usernameField: 'email' }, authenticateUser))
passport.serializeUser((user, done) => done(null, user.id))
passport.deserializeUser((id, done) => {
return done(null, getUserById(id))
})
}
module.exports = initialize
Archivo server.js
if (process.env.NODE_ENV !== ‘production’) {
require(‘dotenv’).config()
}
const express = require(‘express’)
const app = express()
const bcrypt = require(‘bcrypt’)
const passport = require(‘passport’)
const flash = require(‘express-flash’)
const session = require(‘express-session’)
const methodOverride = require(‘method-override’)
const initializePassport = require(‘./passport-config’)
initializePassport(
passport,
email => users.find(user => user.email === email),
id => users.find(user => user.id === id)
)
const users = []
app.set(‘view-engine’, ‘ejs’)
app.use(express.urlencoded({ extended: false }))
app.use(flash())
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(methodOverride(‘method’))
app.get(‘/’, checkAuthenticated, (req, res) => {
res.render(‘index.ejs’, { name: req.user.name })
})
app.get(‘/login’, checkNotAuthenticated, (req, res) => {
res.render(‘login.ejs’)
})
app.post(‘/login’, checkNotAuthenticated, passport.authenticate(‘local’, {
successRedirect: ‘/’,
failureRedirect: ‘/login’,
failureFlash: true
}))
app.get(‘/register’, checkNotAuthenticated, (req, res) => {
res.render(‘register.ejs’)
})
app.post(‘/register’, checkNotAuthenticated, async (req, res) => {
try {
const hashedPassword = await bcrypt.hash(req.body.password, 10)
const users = new User({
name: req.body.name,
email: req.body.email,
password: hashedPassword
})
await users.save()
res.redirect(‘/login’)
}
catch(err){
console.log(err)
res.redirect(‘/register’) }
})
app.delete(‘/logout’, (req, res) => {
req.logOut()
res.redirect(‘/login’)
})
function checkAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next()
}
res.redirect(‘/login’)
}
function checkNotAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return res.redirect(‘/’)
}
next()
}
app.listen(3000)
Estoy utilizando una base de datos mongoDb para mi aplicación y quiero almacenar los usuarios en mi base de datos. He realizado los cambios necesarios en la ruta de registro y puedo almacenar los datos en mi base de datos con éxito.
app.post(‘/register’, checkNotAuthenticated, async (req, res) => {
try {
const hashedPassword = await bcrypt.hash(req.body.password, 10)
const users = new User({
name: req.body.name,
email: req.body.email,
password: hashedPassword
})
await users.save()
res.redirect(‘/login’)
}
catch(err){
console.log(err)
res.redirect(‘/register’) }
})
El problema es cuando intento iniciar sesión con los datos de usuario almacenados, sigo recibiendo el siguiente error.
Error: se requieren argumentos de datos y hash
en Object.compare (C:\AIT715\reactlogin\node_modules\bcrypt\bcrypt.js:208:17)
en C:\AIT715\reactlogin\node_modules\bcrypt\promises.js:29:12
en nueva promesa (<anónimo>)
en Object.module.exports.promise (C:\AIT715\reactlogin\node_modules\bcrypt\promises.js:20:12)
en Object.compare (C:\AIT715\reactlogin\node_modules\bcrypt\bcrypt.js:204:25)
en Strategy.authenticateUser [como verificar] (C:\AIT715\reactlogin\passport-config.js:14:24)
en processTicksAndRejections (internal/process/taskqueues.js:95:5)
He intentado hacer los siguientes cambios en el archivo passport-config.js, pero no ha funcionado.
const LocalStrategy = require(‘passport-local’).Strategy
const bcrypt = require(‘bcrypt’)
const User = require(‘./models/user’)
function initialize(passport, getUserByEmail, getUserById) {
const authenticateUser = async (email, password, done) => {
const user = await User.find({email:email});
console.log(user);
if (user == null) {
return done(null, false, { message: ‘No hay ningún usuario con ese correo electrónico’ })
}
try {
if (await bcrypt.compare(password, user.password)) {
return done(null, user)
} else {
return done(null, false, { message: ‘Contraseña incorrecta’ })
}
} catch (e) {
return done(e)
}
}
“`
Además, cuando utilizo console.log(user) puedo ver los datos, pero cuando intento console.log(user.email) obtengo undefined. ¿Alguien puede sugerir qué estoy haciendo mal aquí o qué cambios debo hacer en el archivo passport-config para que esto funcione? Cualquier ayuda es muy apreciada.</anónimo>
davy.ai
Parece que el método
User.find()
devuelve un array de objetos y estás intentando comparar la contraseña con un array en lugar de con un objeto. Puedes intentar cambiar el código y usar el métodoUser.findOne()
, el cual debería devolver un solo objeto:Y para acceder a la propiedad del correo electrónico, debes utilizar
user[0].email
ouser.email
si usasfindOne()
.Esto debería solucionar el error y permitirte comparar la contraseña con la contraseña del usuario correctamente.