DanyZift DanyZift - 5 months ago 26
Node.js Question

NodeJS Passport

I setup passport on nodejs and have it working with mongoose for allowing users to login and create new accounts.

app.js:

var express = require('express')
, app = module.exports = express.createServer()
, passport = require('passport')
, LocalStrategy = require('passport-local').Strategy
, routes = require('./routes/index')(app) //index loads in multiple routes
, MongoDBConnection = require('./database/DatabaseConnector').MongoDBConnection;

// Configuration
app.configure(function(){
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({ secret: 'justdoit' }));
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(__dirname + '/public'));
});

var mongoDbConnection = new MongoDBConnection();

passport.serializeUser(function(user, done) {
done(null, user.id);
});

passport.deserializeUser(function(id, done) {
mongoDbConnection.findUserById(id, function(err, user){
done(err, user);
});
});

passport.use(new LocalStrategy(
function(username, password, done) {
process.nextTick(function () {
mongoDbConnection.findUser(username, function(err, user) {
//conditions....
});
});
}
));

app.get('/', function(req, res){
res.render('index', { title: "Index", user: req.user });
});

app.get('/account', ensureAuthenticated, function(req, res){
res.render('account', { title: "Account", user: req.user });
});

app.get('/login', function(req, res){
res.render('login', { title: "Login", user: req.user, message: req.flash('error') });
});

app.post('/login',
passport.authenticate('local', {
successRedirect: '/account',
failureRedirect: '/login',
failureFlash: true })
);

function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}


My problem is the app.js (which is where the passport code is) file is getting a bit large and I tried to move the passport sections into its own script and have the routes outside the app.js and in its own auth.js route file and then reference the routes via the app.js. It works for other routes but for passport related ones such as login it doesnt appear to fire the passport.authenicate() function.

Is there anyway I can put passport routes and functions into its own file and call it/load it from app.js?

auth.js:

module.exports = function(app){

passport.serializeUser(function(user, done) {
done(null, user.id);
});

passport.deserializeUser(function(id, done) {
mongoDbConnection.findUserById(id, function(err, user){
done(err, user);
});

});

passport.use(new LocalStrategy(
function(username, password, done) {
process.nextTick(function () {

mongoDbConnection.findUser(username, function(err, user) {

if (err) {
return done(err);
}
if (!user) {
return done(null, false, { message: 'Unknown user ' + username });
}

if (user.password != password) {
return done(null, false, { message: 'Invalid password' });
}

return done(null, user);
});
});
}
));

app.get('/', function(req, res){
res.render('index', { title: "Index", user: req.user });
});

app.get('/account', ensureAuthenticated, function(req, res){
console.log("directing to the account page....");
res.render('account', { title: "Account", user: req.user });
});

app.get('/login', function(req, res){
res.render('login', { title: "Login", user: req.user, message: req.flash('error') });
});

app.post('/login',
passport.authenticate('local', {
successRedirect: '/account',
failureRedirect: '/login',
failureFlash: true })
);

function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}
}

Answer

This is what I do. Please comment if you need more help tailoring it to your code.

First Step

Put your passport code in a separate file. e.g. pass.js. (I see you have already done that) Then, in that file, put all the code inside this:

module.exports = function(passport, LocalStrategy){

};

Remember to add to the function input anything else that you are using. In your case, besides passport and LocalStrategy, you will probably need to add mongoDbConnection as an input too.

Second Step

In your app.js, include this line. Just before "app.listen" if possible to ensure that everything has been properly defined/declared/included.

require('./pass.js')(passport, LocalStrategy);

Explanation

The "wrapper" in step one defines the chunk of code you will be including into your app. The "require" in step two is the code that actually includes it. You are basically defining the entire "pass.js" file as a function and passing it the tools it needs to carry out the code (passport, LocalStrategy etc)

In your case, you will probably need to modify my code to:

module.exports = function(passport, LocalStrategy, mongoDbConnection){

};

require('./pass.js')(passport, LocalStrategy, mongoDbConnection);

This should works. I googled about this a while ago and this appears to be the "correct" way to break up your app.js (I say this with great trepidation though :) ). Feel free to comment if you need anymore help.