I m new in NODE js. so just need to know can we check session in one place rather than applying checks at each method.
This is possible to use single check at server.js for session management.
Thanks in advance
Please make use of express middleware
app.use( function(req, res, next) {
// req.session #use this object
next();
});
make it into a global middleware function
app.use(function(req, res, next) {
if (req.session && req.session.user) {
User.findOne({ email: req.session.user.email }, function(err, user) {
if (user) {
req.user = user;
delete req.user.password;
req.session.user = user;
res.locals.user = user;
}
next();
});
} else {
next();
}
});
Related
so my route (for '/dash') looks like this:
// validating using JWT
router.post('/dash', passport.authenticate('jwt', {session: false}), function (req, res) {
res.json({'success': true});
});
// validating using LOCAL
router.post('/dash', authenticationHelpers.isAuth, function (req, res) {
res.json({'success': true});
});
// authenticationHelpers.isAuth
function isAuth(req, res, next) {
if (req.isAuthenticated())
return next();
res.status(401).json({"authenticated": false});
}
So, how do I use both Local & JWT Strategy on same app (on same route) ? How do I combine them both.
Note: Local for web app, JWT for mobile app
Finally figured it out.
Modified isAuth function:
function isAuth(req, res, next) {
if (req.headers.authorization) {
passport.authenticate('jwt', {session: false}, function (err, user, info) {
if ((!err || !info) && user) {
req.user = user;
return next();
}
res.status(401).json({authenticated: false, message: "Login expired."});
})(req, res, next);
} else {
if (req.isAuthenticated())
return next();
res.status(401).json({authenticated: false});
}
}
Suggestions are welcomed...
I am trying to write a code for user login authentication in express using express-session
This is my accounts.js api
.use(bodyParser.urlencoded())
.use(bodyParser.json())
.use(session({ secret: 'hcdjnxcds6cebs73ebd7e3bdb7db73e' }))
.get('/login', function (req, res) {
res.sendfile('public/login.html');
})
.post('/login', function (req, res) {
var user = {
username : req.body.username,
password : hash(req.body.password)
};
var collection = db.get('users');
collection.findOne (user, function (err, data) {
if (data) {
req.session.userId = data._id;
res.redirect('/');
} else {
res.redirect('/login');
}
});
})
.get('/logout', function (req, res) {
req.session.userId = null;
res.redirect('/');
})
.use(function (req, res, next) {
if (req.session.userId) {
var collection = db.get('users');
collection.findOne({ _id : new ObjectId(req.session.userId)}, function (err, data) {
req.user = data;
});
}
next();
});
module.exports = router;
And this is my server.js code
var express = require('express'),
api = require('./api'),
users = require('./accounts'),
app = express();
app
.use(express.static('./public'))
.use('/api', api)
.use(users)
.get('*', function (req, res) {
if (!req.user) {
res.redirect('/login');
} else {
res.sendfile(__dirname + '/public/main.html');
}
})
.listen(3000);
My problem is, in server.js, req.user is getting null value that's why i am not able to login. But in account.js req.user getting user data which is not reflecting in server.js.
Again, if in accounts.js, I am placing next() inside the if (req.session.userId) statement, I am able to get user data in server.js but it creating problem in logout.
Please help me out in this.
Your accounts.js is executing next() before your collection query returns, so it makes sense that your req.user is undefined in your middleware later on. To fix it, try this:
.use(function (req, res, next) {
if (req.session.userId) {
var collection = db.get('users');
collection.findOne({ _id : new ObjectId(req.session.userId)}, function (err, data) {
req.user = data;
next();
});
} else {
next();
}
});
As a side note, you're very much reinventing the wheel here by implementing user login yourself. I would reccommend taking take a look at passportjs for doing user login like this.
I have the following working code to authenticate through the passport-local strategy:
app.post('/api/login', passport.authenticate('local-login', {
successRedirect : '/api/login/success',
failureRedirect : '/api/login/error',
failureFlash : true
}));
app.get('/api/login/error', function(req, res) {
res.send(401, {error: req.flash('loginMessage')});
});
app.get('/api/login/success', function(req, res) {
res.send(200, {user: req.user});
});
However, ideally I want to handle the errors and success messages from one express route, and not redirect to two extra routes.
Is this possible? I tried using a 'custom callback' but that seemed to error out on serializing users for some reason.
You can use custom callback, such as:
passport.authenticate('local', function (err, account) {
req.logIn(account, function() {
res.status(err ? 500 : 200).send(err ? err : account);
});
})(this.req, this.res, this.next);
In err object you can find all needed errors, which was appeared at authentication.
Are you using Mongoose?
Try adding this to your server.js/index.js
var User = mongoose.model('User');
passport.use(new LocalStrategy(User.authenticate()));
passport.use(User.createStrategy());
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
This to your routes index.js
var auth = require('./auth');
app.post('/api/auth/login', passport.authenticate('local'),auth.login);
auth.js:
var UserModel = require('../models/user');
var User = new UserModel();
exports.login = function(req, res) {
var user = req.user;
req.login(user, function(err) {
//if error: do something
return res.status(200).json(user)
});
};
Add this to model index.js
var passportLocalMongoose = require('passport-local-mongoose');
userSchema.plugin(passportLocalMongoose, {
usernameField: 'email',
usernameLowerCase: 'true'
});
I'm making a lot of assumptions on structure and packages here. but this should work
EDIT
For custom callbacks:
app.get('/login', function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/login'); }
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/users/' + user.username);
});
})(req, res, next);
});
Here you instead of res.redirect you can use something like return res.status(404).json("Not Found)
See docs for more information : http://passportjs.org/guide/authenticate/
It seems whenever I call Passport's ensureAuthenticated middleware, it causes the passport.deserializeUser function to be called upwards 6-7 additional times. I'm not sure if it's my app's structure via Express, Sequelize, or the way Passport is being imported. For this reason, I'm going to lay out a few files in hopes of finding where its gone astray.
Here is how I have everything structured
application/
auth/
models/
node-modules/
public/
routes/
views/
app.js
My assumption is it's either because the middleware is not a singleton, and/or it's because my routing is set-up oddly. Note: I followed this guide on setting up a singleton sequelize approach.
./app.js
// .. imports
app.set('models', require('./models')); // singleton ORM (my assumption)
// .. session stuff
app.use(passport.initialize());
app.use(passport.session());
app.use(require('./auth'));
// .. etc
app.use('/', require('./routes')); // routing style possible issue?
// .. create server
./auth/index.js
module.exports = function () {
var express = require('express')
, passport = require('passport')
, Local = require('passport-local').Strategy
, app = express();
passport.use(new Local(
function(username, password, done) {
app.get('models').User.find({
where: {
username: username,
password: password
}
}).done(function (err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false, { message: 'Invalid login' });
}
return done(null, user);
});
}
));
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
app.get('models').User.find(id).done(function(err, user) {
done(err, user);
});
});
return app;
}();
./auth/middleware.js
exports.check = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect('/login')
};
exports.is = function(role) {
return function (req, res, next) {
if (req.usertypes[req.user.type] === role) next();
else res.redirect('back');
}
};
./routes/index.js
module.exports = function () {
var express = require('express')
, app = express();
app.get('/', function (req, res) {
if (!req.user) res.redirect('/login');
else res.redirect('/' + req.usertypes[req.user.type]);
});
app.use('/admin', require('./admin'));
app.use('/another1', require('./another1')); // yadda
app.use('/another2', require('./another2')); // yadda
app.use('/login', require('./login'));
app.get('/logout', function(req, res){
req.logout();
res.redirect('/');
});
return app;
}();
and Finally, ./routes/admin.js
module.exports = function () {
var express = require('express')
, auth = require('../auth/middleware')
, admin = express();
// auth.check seems to be what's firing the multiple queries:
// Executing: SELECT * FROM `users` WHERE `users`.`id`=1 LIMIT 1;
// 6 times from the looks of it.
admin.get('/', auth.check, auth.is('admin'), function (req, res) {
res.render('admin', {
username: 'req.user.username'
});
});
admin.get('/users.json', auth.check, auth.is('admin'), function (req, res) {
res.contentType('application/json');
admin.get('models').User.findAll().done(function (err, users) {
if (users.length === 0) {
// handle
} else {
res.send(JSON.stringify(users));
}
});
});
admin.post('/adduser', auth.check, auth.is('admin'), function (req, res) {
var post = req.body;
admin.get('models').User.create(post).done(function (err, user) {
if (!err) {
res.send(JSON.stringify({success: true, users: user}));
} else {
res.send(JSON.stringify({success: false, message: err}));
}
});
});
return admin;
}();
I know it's a bit of code, but I have a feeling it's something very very simple. Any guidance would be much appreciated.
It's because you are using your passportJS session middleware earlier than your static files. Because of that your all static file calls (like <img src="...">) passing thru session middleware and calling deserializeUser().
Solution
Use your session middleware after app.use(express.static(...)) in your app.js file.
Check jaredhandson's this GitHub issue answer for more details : https://github.com/jaredhanson/passport/issues/14#issuecomment-4863459
I just had that problem. The reason all your static assets are running through your middleware is because you are either not defining what are static assets or you're defining it too late. I had to tell it to use /assets as the base for the public files, and then you have to make sure it comes before your other app.use definitions.
app.use('/assets', express.static(path.join(__dirname, 'public')));
I have a express route like this:
app.get('/', auth.authOrDie, function(req, res) {
res.send();
});
where authOrDie function is defined like that (in my auth.js module):
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.send(403);
}
});
Now, when the user is not authenticated, I would like to verify if the http request has a Authorization (Basic) header. To do that, I would like to use the great connect middleware basicAuth().
As you know, Express is built on top of Connect, so I can use express.basicAuth.
The basicAuth is generally used like that:
app.get('/', express.basicAuth(function(username, password) {
// username && password verification...
}), function(req, res) {
res.send();
});
But, I would like to use it in my authOrDie function like that:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else if {
// express.basicAuth ??? ******
} else {
res.send(403);
}
});
****** How can I call the basicAuth function with the good parameters (req ? res ? next ? ...).
Thanks.
Calling the express.basicAuth function returns the middleware function to call, so you'd invoke it directly like this:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
return express.basicAuth(function(username, password) {
// username && password verification...
})(req, res, next);
}
});