session user sometimes has value sometimes undefined - javascript

I have a little problem, and I have already spent one day trying to solve it with no results. I used passport.js, and the login and session work well, if I access address without login then I will be kicked to login page. But I have a little problem, when I fill datasource of datatable (cart.html) with routing from index.js, req.session.user will be undefined. But I checked in cart.html in routing of index.js, it has a value. I would appreciate anyone who can help me, thanks in advance.
Here is my routing cart.html of index.js
app.get('/cart',(req,res)=>{
//res.render('cart');
if (req.session.user) {
var userdata=req.session.passport.user;
res.render('cart',{username: userdata[0].USER,level:userdata[0].IDLEVEL});
}else {
res.redirect('/login');
}
});
here my passport :
passport.use(new LocalStrategy({passReqToCallback: true},
function(req,username, password, done) {
db.getConnection(function (err, connection) {
SQL="SELECT * FROM muser WHERE USER = ? and PASSWORD = ?";
connection.query(SQL, [username, password], function (err, rows) {
connection.release();
if(err) return done(err);
// if user not found
if (rows.length <= 0) {
return done('Cannot login');
//console.log(username+' '+password);
}
req.session.user=rows;
return done(null, rows);
});
});
}
));
passport.serializeUser(function(user, done) {
done(null, user);
});
passport.deserializeUser(function(id, done) {
db.getConnection(function (err, connection) {
connection.query('SELECT * FROM muser WHERE ID = ?', [id], function(err, user) {
connection.release();
if(err) return done(err);
done(null, user);
});
});
});
function isAuthenticated(req, res, next) {
if (req.isAuthenticated()) return next();
res.redirect('/login');
}
app.get('/', isAuthenticated, function(req, res) {
res.render('home');
});
app.use(passport.initialize());
app.use(passport.session());
app.post('/login',
passport.authenticate('local', {
failureRedirect: '/login' }),
function(req, res) {
if (req.isAuthenticated()) {
res.redirect('/home');
}else {
res.redirect('/');
}
}
);
here my cart.html's codes
$("#dgcart").DataGrid({
dataSource: "http://192.168.10.120:5556/getcart" (routing below to get data of cart)
...});
here my bug cannot access req.session.user will be undefined
app.get('/getcart',(req,res)=>{
if (req.session.user) {
var userdata=req.session.passport.user;
SQL="SELECT TC.ID,TC.IDITEM,TC.KODEBARANG,TC.NAMA,SUM(TC.QTY) AS QTY,TC.PRICE, TC.SUBTOTAL"+'\n'+
"FROM cart TC "+'\n'+
"WHERE TC.IDUSER="+userdata[0].ID+'\n'+
"GROUP BY TC.KODEBARANG,TC.IDITEM,TC.KODEBARANG,TC.NAMA,TC.PRICE,TC.SUBTOTAL,TC.IDUSER";
rowsalasql=alasql(SQL);
console.log(SQL+' '+rowsalasql);
res.send(JSON.stringify(rowsalasql));
}else {
... will be here because undefined
}
});

Related

Multiple authentication not working passport.js

I am trying to authenticate multiple user through multiple strategies. I have 2 table first is User table and second is employee but it's working when i try to login it show the error
User not exist
when i use just single authentication strategy it's work but when i use multiple strategy it shows error
Auth.js
const LocalStrategy = require('passport-local').Strategy
const bcrypt = require('bcrypt')
const User = require('../models/authUserModel')
const Employee = require('../models/employeeModel')
module.exports = function (passport) {
passport.use("user-local",
new LocalStrategy({usernameField: "email"}, function (email, password, done) {
User.findOne({email: email})
.then(user => {
if (!user) {
return done(null, false, ({message: 'Email not exist'}))
}
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'}))
}
})
}).catch(err => console.log(err))
})
)
passport.use('local',
new LocalStrategy({usernameField:"email"}, function (email, password, done){
Employee.findOne({email:"email"})
.then(user=>{
if(!user){
return done(null, false,'employee not exist')
}
bcrypt.compare(password, user.password, (err, isMatch)=>{
if(isMatch){
return done(null, user)
}
else {
return done(null, false, 'password or email is incorrect')
}
})
}).catch(err=>console.log(err))
})
)
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
}
Login.js
let express = require('express');
let router = express.Router();
const passport = require('passport')
router.get('/login', function(req, res, next) {
res.render('login');
})
router.post('/login', function (req, res, next) {
passport.authenticate("user-local", function (err, user, info) {
if (err) {
return next(err)
}
if (!user) {
console.log('User not exist')
return res.render('login')
}
req.logIn(user, function (err) {
if (err) {
return next(err)
}
req.session.isLoggedIn = true
req.session.user = user
req.session.save(err => {
console.log(err)
if (req.isAuthenticated()) {
return res.redirect('/customerMenu')
}
console.log('user not exist')
return res.render('login')
})
})
})(req, res, next)
passport.authenticate('local', function (err, user, info){
if(err){
return next(err)
}
if(!user)
{
console.log("employee not exist")
return res.render('login')
}
req.logIn(user,function (err){
if(err){return next(err)}
req.session.isLoggedIn = true
req.session.user = user
req.session.save(err=>{
console.log(err)
if (req.isAuthenticated()) {
return res.redirect(200,'/employeeMenu')
}
console.log('user not exist')
return res.render('login')
})
})
})(req, res, next)
})
function isLoggedIn(req, res, next){
if(req.isAuthenticated()){
req.isLogged = true
return next();
}
else{
req.isLogged = false
return next()
}
}
module.exports = isLoggedIn
module.exports = router
I think you need to edit your .serializeUser() and .deserializeUser() functions so that passport knows what type of user you are trying to serialize and deserialize.
The way I have done it in the past is by using a SessionConstructor that puts both the user's id and the type of user they are inside an object. You can then use this in your deserialize function to figure out which usertype you are trying to sign in.
function SessionConstructor(userId, userGroup){
this.userId = userId;
this.userGroup = userGroup;
}
passport.serializeUser((user, done) => {
let userGroup = 'user';
if (//condition to tell if it is the other user type){
userGroup = 'employee';
};
let sessionConstructor = new SessionConstructor(user.id, userGroup)
done(null, sessionConstructor);
});
passport.deserializeUser((sessionConstructor, done) => {
if (sessionConstructor.userGroup == 'user'){
User.findById(sessionConstructor.userId).then(user => done(null, user));
} else if (sessionConstructor.userGroup == 'employee'){
Employee.findById(sessionConstructor.userId).then( employee=> done(null, employee));
}
});
You will however need to think of a condition for the if statement inside of .serializeUser() that will tell you which type of user it is. If you include a unique identifier inside of the user object that is sent to .serializeUser(), then you can check that to tell. For example have a key called employee inside your user object where the value is true if its an employee submitting it, and false otherwise. If you choose this implementation it would look something like this.
passport.serializeUser((user, done) => {
let userGroup = 'user';
if (user.employee){
userGroup = 'employee';
};
let sessionConstructor = new SessionConstructor(user.id, userGroup)
done(null, sessionConstructor);
});
Outisde of that I think the below code should work, but feel free to ask any questions about this method and I'll do my best to answer!
Here is a link to where I learned about how to do this.

How to handle Express Sessions?

I'm trying to deal with authentication sessions in Node.js, Express, Passport app.
I made lines of code to use express-session and it still can't auth even when I register new user.
Here is strategy.
// Local Strategy
passport.use(new LocalStrategy({ usernameField: 'email' }, function(username, password, done){
User.findOne({ 'email': username }, function(err, user){
if(err) throw err;
if(!user){
return done(null, false, {type: "danger", message: 'No user found'});
}
// Match Password
bcrypt.compare(password, user.password, function(err, isMatch){
if(err) throw err;
if(isMatch){
return done(null, user);
} else {
return done(null, false, {type: "danger", message: 'Wrong password'});
}
});
});
}));
Here are serializers.
passport.serializeUser(function(user, done) {
console.log(user.id);
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
console.log(user.id);
done(err, user);
});
});
Here is login and register route.
// Login page and form
router.get('/login', function(req, res) {
res.render('login');
});
router.post('/login', passport.authenticate('local',
{successRedirect: '/chat',
failureRedirect: '/login'}));
// Register page and form
router.get('/register', function(req, res) {
let errors = [];
res.render('register', { 'errors': '' });
});
router.post('/register', [
check('name').notEmpty().withMessage('Name field is empty'),
check('surname').notEmpty().withMessage('Surname field is empty'),
check('email').notEmpty().withMessage('E-mail is empty'),
check('password').notEmpty().withMessage('Password field is empty'),
check('password_confirm').notEmpty().withMessage('Password confirmation field is empty'),
check("password", "Passwords don't match")
.custom((value,{req}) => {
if (value !== req.body.password_confirm) {
throw new Error("Passwords don't match");
} else {
return value;
}
}),
], function(req, res) {
const { name, surname, email, password } = req.body;
let errors = validationResult(req);
console.log(errors.errors);
if(!errors){
res.render('register', { 'errors': errors.errors });
console.log('ebebe');
} else {
console.log('oooo');
let NewUser = new User ({
name, surname, email, password
});
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
NewUser.password = hash;
NewUser.save();
});
});
res.redirect('/chat');
}
});
Here is protected route.
router.get('/chat', (req, res) => {
if(req.isAuthenticated()) {
res.send('definitely secure page');
console.log(req.user);
console.log(req.isAuthenticated());
} else {
res.send('ebebe');
console.log(req.user);
console.log(req.isAuthenticated());
}
});
How to make it work properly and what am I doing wrong?
Here is a way to do it. You can use something like jsonwebtoken in combination with express-session and write a middleware function to check if the token is valid and use it to protect the routes that you want to protect. Here are some snippets of code that I hope will help guide you in the right direction.
First you can write a function like this in your UserSchema so you can use it later to generate a jwt token when the user logs in
var jwt = require('jsonwebtoken');
UserSchema.methods.generateJWT = function() {
var today = new Date();
var exp = new Date(today);
exp.setDate(today.getDate() + 60);
return jwt.sign({
id: this._id,
username: this.username,
exp: parseInt(exp.getTime() / 1000),
}, secret);
};
then in the login route you can use it to generate a token.
router.post('/login', passport.authenticate('local',
failureRedirect: '/login'}), function(req, res) {
req.user.token = user.generateJWT();
req.session.token = req.user.token;
res.redirect('/dashboard')
});
and then you can write the middleware
function auth(req, res, next) {
//console.log(req.session.token)
if (req.session.token) {
const token = req.session.token
let decoded = jwt.verify(token, secret)
console.log(decoded)
User.findById(decoded.id, function(err, user) {
if (err || !user) {
return res.redirect('/')
}
//console.log(user)
res.locals.user = user
req.user = user
next()
})
} else {
return res.redirect('/')
}
}
and then you can protect your routes with it
router.get('/protected', auth, function(req, res) {
})

Cannot read property 'admin' of undefined

I have this problem in the time i am in admin routes and i try to add a new article or a new image in my database , the same things happen even when i want to update something ....
this is my codes ?
exports.isAdmin = (req, res, next) => {
if (req.isAuthenticated() && res.locals.user.admin == 1) {
next();
} else {
req.flash("danger", "please log in as admin");
res.redirect("/users/login");
}
}
var LocalStrategy = require("passport-local").Strategy;
var User = require("../models/user");
var bcrypt = require("bcryptjs");
module.exports = function (passport) {
passport.use(new LocalStrategy(function (username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err)
console.log(err);
if (!user) {
return done(null, false, { message: "No user found" });
}
bcrypt.compare(password, user.password, function (err, isMatch) {
if (err) console.log(err);
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Wrong password" });
}
})
});
}));
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
}
Anyone one can help the problem is i think in res.locals.user.admin but in other admin routes works ok but only when i want to add a new and edit a think happen this problem

Passportjs: Cannot read property 'connection' of undefined at Strategy._verify

Using passportjs for authentication in my node.js application but getting the error above. This is my code below
app.js
passport.use(new LocalStrategy({usernameField: 'email'},function(email, password, res, done) {
res.locals.connection.query('SELECT id, password FROM users WHERE email = ?', [email], function(err, user) {
console.log(user);
if (err) {return done(err)};
if (user.length === 0) {
done(null, false);
};
const hash = user[0].password.toString();
console.log(hash);
bcrypt.compare(password, hash, function(err, res) {
if (res === true) {
return done(null, {user_id: user[0].id});
} else {
return done(null, false);
}
});
});
}
));
index.js
router.post('/', passport.authenticate('local', {
successRedirect: 'home',
failureRedirect: '/'
}));
What could be wrong with my code?

Passport + Node.js / Automatic login after adding user

I am using passport for authentication and session handling. Everything works fine so far. I implemented a "Sign in" form to add new users to the app. After a user is added I would like to log him/her in automatically.
What is the best way to achieve this - should I redirect to "/login" with the user credentials or is there another/better way(call serializeUser) to do that?
So far I think I did not really understand the way the "done" function (in serializeUser and LocalStrategy) is working or what it is doing ...
Here is my code:
passport.serializeUser(function(user, done) {
done(null, user._id);
});
passport.deserializeUser(function(id, done) {
authProvider.findUserById('users', id, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy( function(email, password, done) {
authProvider.getUserByEmail('users', email, function(error, user){
if(error) { return done(error); }
if (!user) { return done(null, false, { message: 'Unknown user ' + email });}
if (user.password != password) { return done(null, false);}
return done(null, user);
});
}
));
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login'}),
function(req, res) { res.redirect('/');});
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
if(error){
res.redirect('/sign');
} else {
res.redirect('/');
}
});
});
Does someone know how to do this?
Based on the Passport Guide req.login() is intended for this exact purpose.
This function is primarily used when users sign up, during which req.login() can be invoked to automatically log in the newly registered user.
Modifying krasu's code:
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
if ( error ){
res.redirect('/sign');
} else {
req.login(user, function (err) {
if ( ! err ){
res.redirect('/account');
} else {
//handle error
}
})
}
});
});
The potential error from the login() callback would come from your serializeUser() function.
Please use code from the #Weston answer bellow, because it's more universal and straightforward
Should look something like this
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
if(error){
res.redirect('/sign');
} else {
passport.authenticate('local')(req, res, function () {
res.redirect('/account');
})
}
});
});
I don't sure about name of strategy, but by default LocalStrategy should provide 'local' name
http://passportjs.org/guide/authenticate/
Try with:
app.post('/sign', function(req, res){
authProvider.saveUser(...do stuff), function(error, user){
passport.authenticate('local', (err, user) => {
req.logIn(user, (errLogIn) => {
if (errLogIn) {
return next(errLogIn);
}
return res.redirect('/account');
});
})(req, res, next);
});
});

Categories

Resources