NodeJS Express Passport Multiple files
Passport
This post to explain how it works in express3-multiple-files in pasport-local
Original code is passport-local created by mjhea0.
My other posts about Passport is following
Separate files
function
| Source file | Description |
|---|---|
| routes/basic.js | basic route(only render ejs) |
| routes/user.js | user related routes |
| config/dbschema.js | db schema and connection |
| config/pass.js | passport related work |
| app.js | main part |
Separtes routing parts, passport parts and mongodb parts.
layout views/
| layout file | Description |
|---|---|
| footer.ejs | Footer |
| header.ejs | Header |
| index.ejs | Top page(after signin) |
| login.ejs | Sign in page |
Logic
app.js
var express = require('express')
, http = require('http')
, path = require('path')
, app = express()
, db = require('./config/dbschema')
, pass = require('./config/pass')
, passport = require('passport')
, basic_routes = require('./routes/basic')
, user_routes = require('./routes/user');
// all environments
app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.cookieParser());
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.session({ secret: 'keyboard cat' }));
// Initialize Passport! Also use passport.session() middleware, to support
// persistent login sessions (recommended).
app.use(passport.initialize());
app.use(passport.session());
app.use(app.router);
app.use(express.static(path.join(__dirname, 'public')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
// Basic pages
app.get('/', basic_routes.index);
// User pages
app.get('/account', pass.ensureAuthenticated, user_routes.account);
app.get('/login', user_routes.getlogin);
app.post('/login', user_routes.postlogin);
//app.get('/admin', pass.ensureAuthenticated, pass.ensureAdmin(), user_routes.admin);
app.get('/logout', user_routes.logout);
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});
pass.js
var passport = require('passport')
,LocalStrategy = require('passport-local').Strategy
, db = require('./dbschema');
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
db.userModel.findById(id, function (err, user) {
done(err, user);
});
});
passport.use(new LocalStrategy(function(username, password, done) {
db.userModel.findOne({ username: username }, function(err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false, { message: 'Unknown user ' + username }); }
user.comparePassword(password, function(err, isMatch) {
if (err) return done(err);
if(isMatch) {
return done(null, user);
} else {
return done(null, false, { message: 'Invalid password' });
}
});
});
}));
//Simple route middleware to ensure user is authenticated. Otherwise send to login page.
exports.ensureAuthenticated = function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) { return next(); }
res.redirect('/login')
}
dbschema.js
var mongoose = require('mongoose'),
bcrypt = require('bcrypt'),
SALT_WORK_FACTOR = 10;
exports.mongoose = mongoose;
// Database connect
var uristring =
process.env.MONGOLAB_URI ||
process.env.MONGOHQ_URL ||
'mongodb://localhost/test';
var mongoOptions = { db: { safe:true }};
mongoose.connect(uristring, mongoOptions, function(err, res) {
if (err) {
console.log('ERROR connecting to:' + uristring + '. ' + err);
}
else {
console.log('Successfully connected to: ' + uristring);
}
});
var Schema = mongoose.Schema;
var ObjectId = Schema.ObjectId;
// User Schema
var userSchema = new Schema({
username: { type: String, required: true, unique: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true},
admin: { type: Boolean, required: true },
});
//Bcrypt middleware
userSchema.pre('save', function(next) {
var user = this;
if(!user.isModified('password')) return next();
bcrypt.genSalt(SALT_WORK_FACTOR, function(err, salt) {
if(err) return next(err);
bcrypt.hash(user.password, salt, function(err, hash) {
if(err) return next(err);
user.password = hash;
next();
});
});
});
//Password verification
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if(err) return cb(err);
cb(null, isMatch);
});
};
// Export user model
var userModel = mongoose.model('User', userSchema);
exports.userModel = userModel;
user.js
var passport = require('passport');
exports.account = function(req, res) {
res.render('account', { user: req.user });
};
exports.getlogin = function(req, res) {
res.render('login', { user: req.user, message: req.session.messages });
};
exports.admin = function(req, res) {
res.send('access granted admin!');
};
//POST /login
//This is an alternative implementation that uses a custom callback to
//acheive the same functionality.
exports.postlogin = function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
req.session.messages = [info.message];
return res.redirect('/login')
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
};
exports.logout = function(req, res) {
req.logout();
res.redirect('/');
};
basic.js
var passport = require('passport');
exports.account = function(req, res) {
res.render('account', { user: req.user });
};
exports.getlogin = function(req, res) {
res.render('login', { user: req.user, message: req.session.messages });
};
exports.admin = function(req, res) {
res.send('access granted admin!');
};
//POST /login
//This is an alternative implementation that uses a custom callback to
//acheive the same functionality.
exports.postlogin = function(req, res, next) {
passport.authenticate('local', function(err, user, info) {
if (err) { return next(err) }
if (!user) {
req.session.messages = [info.message];
return res.redirect('/login')
}
req.logIn(user, function(err) {
if (err) { return next(err); }
return res.redirect('/');
});
})(req, res, next);
};
exports.logout = function(req, res) {
req.logout();
res.redirect('/');
};
Layout
footer.ejs
</body> </html>
header.ejs
<!DOCTYPE html>
<html>
<head>
<title>Passport-Local Example</title>
</head>
<body>
<% if (!user) { %>
<p>
<a href="/">Home</a> |
<a href="/admin">Admin Page</a> |
<a href="/login">Log In</a>
</p>
<% } else { %>
<p>
<a href="/">Home</a> |
<a href="/admin">Admin Page</a> |
<a href="/account">Account</a> |
<a href="/logout">Log Out</a>
</p>
<% } %>
index.ejs
<% include header %>
<% if (!user) { %>
<h2>Welcome! Please log in.</h2>
<% } else { %>
<h2>Hello, <%= user.username %>.</h2>
<% } %>
<% include footer %>
login.ejs
<% include header %>
<% if (message) { %>
<p><%= message %></p>
<% } %>
<form action="/login" method="post">
<div>
<label>Username:</label>
<input type="text" name="username"/><br/>
</div>
<div>
<label>Password:</label>
<input type="password" name="password"/>
</div>
<div>
<input type="submit" value="Submit"/>
</div>
</form>
<p><small>Hint - bob:secret</small></p>
<% include footer %>
