I'm havig trouble understanding how to access the properties of a global variable that is set in the middleware of my application
// app.js
app.use(function (req, res, next) {
res.locals.user = req.user || null;
next();
});
I would have thought I could access the req.user.username in my template (using handlebars), but for some reason it is forcing me to iterate over this object.
A consle.log(req.user) shows:
_id: 5f01f9a861f5b33b42a9e,
username: 'onetap',
email: 'test#gmail.com',
password: '$2b$10$VLBS8ZwPKiaXasdfsiiwfg.wyJ1J5CwTKLjS5zXwAsvukHpNmk0HG2',
createdAt: 2020-07-05T16:02:48.081Z,
__v: 0
}
And in my template I have to use an each loop and can't access the properties directly. the req.user is not an array either.
{{user.username}}//undefined
{{#each user}}
{{username}} //onetap
{{/each}}
passport.js file
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
const mongoose = require("mongoose");
// Load User Model
const User = require("../models/User");
module.exports = function (passport) {
passport.use(
new LocalStrategy({ username: "username" }, (username, password, done) => {
// Match User
User.findOne({
username: username,
}).then((user) => {
if (!user) {
return done(null, false, { message: "Invalid Username" });
}
console.log("Checking password");
// Match password
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Password incorrect" });
}
});
});
})
);
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
};
I was able to fix this by chaning deserialize to:
passport.deserializeUser(function (id, done) {
User.findById(id)
.lean()
.exec(function (err, user) {
done(err, user);
});
});
Related
I'm using Passport js local strategy but I can't redirect from my admin page. it always fails even if the login and password are correct, below is the auth.js and login.js code
login.js
router.get('/', (req, res, next) =>{
if (req.query.fail){
res.render('admin/login', {layout: 'admin.hbs', message: "Usuario e/ou Senha invalidos"});
}else{
res.render('admin/login', {layout: 'admin.hbs', message: null});
}
})
router.post('/',
passport.authenticate('local', { failureRedirect: '/login?fail=true' }),
function(req, res) {
res.redirect('/admin');
});
auth.js
const users = [{
_id: 123,
username: "adm",
password: hashedPassword
}];
console.log(users);
module.exports = function(passport){
function findUser(username){
return users.find(item => item.username === username);
}
function findUserById(id){
return users.find(item => item._id === id);
}
passport.serializeUser((user, done) => {
done(null, user._id);
});
passport.deserializeUser((id, done) => {
try {
const user = findUserById(id);
done(null, user);
} catch (err) {
console.log(err);
return done(err, null)
}
});
passport.use(new localStrategy({
usernameField: 'username',
passwordField: 'password',
},
(username, password, done) => {
try{
const user = findUser(username).then(user);
if(!user) return done(null, false);
const isValid = bcrypt.compare(password, user.password);
if(!isValid) return done(null, false);
return done(null, user);
}
catch(err){
console.log(err);
return done(err, false)
}}));
}
I don't know why it's not working, I wanted help getting into the admin page
I've tried to add a plus parameter to serializeUser method such as email or facebook_id parameter and then I checked that:
if (user.id) {
done(null, user.id);
} else {
done(null, user.email);
}
but it didn't work.
Here is my passport.js file:
module.exports = (passport) => {
passport.serializeUser((user, done) => {
done(null, user.id);
});
passport.deserializeUser((id, done) => {
conn.query("SELECT * FROM user WHERE id = ?", [id], (err, rows) => {
done(err, rows[0]);
});
});
passport.use(
'local-login',
new LocalStrategy({
usernameField: 'login-username',
passwordField: 'login-password',
passReqToCallback: true
},
function (req, username, password, done) {
conn.query("SELECT * FROM user WHERE username = ?", [username], (err, rows) => {
if (err)
return done(err);
if (!rows.length) {
return done(null, false, req.flash('loginMessage', 'No User found!'));
}
if (!bcrypt.compareSync(password, rows[0].password))
return done(null, false, req.flash('loginMessage', 'Wrong Password!'));
return done(null, rows[0]);
})
}
)
);
passport.use(new FacebookStrategy({
clientID: configAuth.facebookAuth.clientID,
clientSecret: configAuth.facebookAuth.clientSecret,
callbackURL: configAuth.facebookAuth.callbackURL
},
function (accessToken, refreshToken, profile, done) {
process.nextTick(function () {
conn.query("SELECT * FROM user WHERE facebook_id = ?", [profile.id], (err, user) => {
if (err)
return done(err);
if (user)
return done(null, user);
else {
let newUser = {
facebook_id: profile.id,
token: accessToken,
email: profile.emails[0].value,
name: profle.name.givenName + ' ' + profile.name.familyName
};
conn.query("INSERT INTO USER (facebook_id, token, email, name) VALUES (?, ?, ?, ?)",
[profile.id, profile.accessToken, profile.emails[0].value, profle.name.givenName + ' ' + profile.name.familyName], (err, rows) => {
if (err)
console.log(err)
return done(null, newUser);
})
}
});
});
}))
};
If I want to login with local account with username it works, but when I want to login with facebook I get the following error:
Error: Failed to serialize user into session
Is there any way to serialize a facebook user and a local user at the same time?
passport.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var user = require('../modal/admin');
exports.passport = (passport) => {
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
(username, password, done, req) => {
console.log(req)
user.findOne(({ username: username }), async (err, user) => {
if (err) { return done(err); }
if (!user) { return done(null, false); }
const cpassword = await bcrypt.compare(password, user.password);
if (!cpassword) { return done(null, false); }
const token = jwt.sign(
{
id:user.id,
username:user.username
},
"shubham"
);
adminRecords = {
token:token
}
req.data = adminRecords ====>>>> Error here
console.log(adminRecords)
return done(null, user, adminRecords);
});
}
))
};
passport.serializeUser(function (user, done) {
done(null, user)
})
passport.deserializeUser(function (id, done) {
user.find(id, function (err, user) {
done(err, user)
});
});
route.js
router.post('/login', passport.authenticate('local'));
It's giving error req.data is not defined. I am using passport local strategy and want to return jwt token in req.data. It is not taking req parameter correctly.
Callback function have only 3 params
passport.use(new LocalStrategy({
usernameField: 'username',
passwordField: 'password'
},
(username, password, done, req) => { // callback function have only 3 params
// Additional codes
Solution try to use middleware when you authenticate
app.use(request, response, next) => { passport.authenticate('local', (err, token, info) => {
if (token) {
request.login(token, () => { // Do your logic });
} else { }
})(request, response, next); });
I'm using passport.js to get a basic signup function established for a Node + Express + Sequelize app. Right now I have an empty database, and am using just the passport-local strategy to get the user's email and password from a form, check this against the database to ensure the email is not associated with another account, and then once this has been established, create the user.
Here are the relevant sections of my code:
./config/passport.js
const db = require('./sequelize');
const passport = require('passport'),
LocalStrategy = require('passport-local').Strategy;
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(user, done) {
db.User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use('local', new LocalStrategy({
emailField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(email, password, done){
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
db.User.findOne({ email : email }, function(err, user) {
// if there are any errors, return the error
if (err)
return done(null, false, {message: err});
// check to see if there's already a user with that email
else if (user) {
return done(null, false, {message: 'User already exists'});
}
else {
return done(null, true, {message: 'User created'});
}
});
});
}
));
module.exports = passport;
app.js
app.post('/signup', function(req, res, next){
const user = req.body;
passport.authenticate('local', function(err, user, info){
if (err){
res.send({success: false, message: 'authentication failed'});
}
if (!user) {
console.log(user);
res.send({message: "user already found"});
}
else{
db.User.create({
email: req.body.username,
password: req.body.password
});
console.log(info);
res.json({message: "user successfully signed up"});
}
})(req, res, next)
});
./config/sequelize
const path = require('path');
const Sequelize = require('sequelize');
const _ = require('lodash');
const config = require('./config');
const db = {};
// create your instance of sequelize
const sequelize = new Sequelize(config.db.name, config.db.username, config.db.password, {
host: config.db.host,
port: config.db.port,
dialect: 'mysql',
storage: config.db.storage
});
//Instantiate the database
sequelize
.authenticate()
.then(function(err) {
console.log('Connection has been established successfully.');
}, function (err) {
console.log('Unable to connect to the database:', err);
});
/* this is where all of the MODELS will be defined for the time being */
const User = sequelize.define('User', {
username: Sequelize.STRING,
email: Sequelize.STRING,
password: Sequelize.STRING
});
sequelize.sync();
db.User = User;
db.Sequelize = Sequelize;
db.sequelize = sequelize;
module.exports = db;
However, when I run the app with the clean database, !user in the app.js file evaluates to false, and I am unable to sign up new users because it would seem to be that the strategy thinks there is already an existing user with that email in the database. What do I need to do to remedy situation?
db.User.findOne({ where: { email : email }})
.then(
function(user) {
if (user) {
return done(null, false, {message: 'User already exists'});
} else {
return done(null, true, {message: 'User created'});
);
Try to change your code
using redirects here (app.js):
app.post('/signup', passport.authenticate('local', {
successRedirect : '/profile',
failureRedirect : '/signup',
failureFlash : true
}));
using promises for sequelize queries (./config/passport.js):
passport.deserializeUser(function(id, done) {
db.User.findById(id).then(function(user) {
done(err, user.dataValues);
})
.catch(function(err){
done(err, null);
});
});
passport.use('local', new LocalStrategy({
emailField : 'email',
passwordField : 'password',
passReqToCallback : true
},
function(req, email, password, done){
process.nextTick(function() {
// find a user whose email is the same as the forms email
// we are checking to see if the user trying to login already exists
db.User.findOne({ where: {email : email }})
.then(function(user) {
if (user !== null) {
done(null, false, {message: 'User already exists'});
}
else {
db.User.create({
email: email,
password: password
})
.then(function(user){
done(null, user);
})
.catch(function(err){
console.log(err);
done(null, false);
});
}
})
.catch(function(err){
// if there are any errors, return the error
return done(null, false, {message: err});
});
});
}
));
I set-up passport on nodejs with mongoose for allowing users to login and create new accounts. Create new account is working but the login part doesn't.
users.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongoose = require('mongoose');
var User = require('../models/user');
router.get('/login', function(req, res, next) {
res.render('login', {
'title': 'Login'
});
});
passport.serializeUser(function(user, done){done(null, user);});
passport.deserializeUser(function(id, done){
User.getUserById(id, function(err, user){
done(err, user);
});
});
passport.use(new LocalStrategy(
function(username, password, done){
User.getUserByUsername(username, function(err, user){
if(err) throw err;
if(!user){
console.log('Unknown User');
return done(null, false,{message: 'Unknown User'});
}
User.comparePassword(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
}else{
console.log('Invalid Password');
return done(null, false, {message: 'Invalid password'});
}
});
});
}
));
router.post('/login', passport.authenticate('local', {successRedirect: '/',failureRedirect: '/users/register', failureFlash:'Invalid username or password'}), function(req,res){
console.log('Authentication Successful');
req.flash('success', 'You are logged in');
res.redirect('/');
});
../models/user.js
var mongoose = require('mongoose');
var bcrypt = require('bcrypt');
mongoose.connect('mongodb://localhost/nodeauth');
var db = mongoose.connection;
var UserSchema = mongoose.Schema({
username: {
type: String,
index: true
},
password: {
type: String, required: true, bcrypt: true
},
email:{
type: String
},
name:{
type: String
},
profileimage:{
type: String
}
});
var User = module.exports = mongoose.model('User', UserSchema);
module.exports.comparePassword = function(candidatePassword, hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err) return callback(err);
callback(null,isMatch);
});
}
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.getUserByUsername = function(username, callback){
var query = {username: username};
User.findOne(query, callback);
}
module.exports.createUser = function(newUser, callback){
bcrypt.hash(newUser.password, 10, function(err, hash){
if(err) throw err;
// Set hashed pw
newUser.password = hash;
// Create User
newUser.save(callback);
});
}
If I create the new user than is working the data are uploading the MongoDB but if I try to Log In it just drop me to the /users/register page I do not have any error
Well it is not doing anything because your login route is not calling anything... check the documentation on http://passportjs.org/docs to see how passport works.
In user.js you need something like
router.get('/login',
passport.authenticate('local'),
function(req, res) {
res.render('login', {
'title': 'Login'
});
});
Then in a separate file you need to setup your authentication strategy, for example:
var passport = require('passport')
, LocalStrategy = require('passport-local').Strategy;
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) {
return done(null, false, { message: 'Incorrect username.' });
}
if (!user.validPassword(password)) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
}
));
Check this tutorial for a step-by-step on implementing local authentication strategy.
http://code.tutsplus.com/tutorials/authenticating-nodejs-applications-with-passport--cms-21619
If you want something more advanced, this code has examples of social authentication strategies (for example, your users can log in using Facebook accounts)
https://github.com/mjhea0/passport-examples
Good luck!