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 %>