route separation with express router and passing instances - node.js

So I'm trying to separate all my routes and organize them. I've manage to do that, but I face an issue. Using express 4, and the router I am having a problem passing an instance of something to a particular route. For example I want to pass passport to the login.js file. How would I do that? Am I doing this the correct way, or is there a better more cleaner solution?
//app.js
var express = require('express');
var passport = require('passport');
var app = express();
require('./routes')(app, passport);
//routes.js
module.exports = function (app, passport) {
app.use('/', require('./routes/index'));
app.use('/', require('./routes/login')(passport));
app.use('/', require('./routes/register')(passport));
};
//login.js
Here passport is undefined.
var express = require('express');
var router = express.Router();
router.get('/login', function (req, res) {
res.render('login', {
title: 'login',
message: req.flash('loginMessage')
});
});
router.post('/login', passport.authenticate('local-login', {
successRedirect : '/profile',
failureRedirect : '/login',
failureFlash : true
}));
module.exports = router;

So there's two ways folks do this, and there's pros and cons to each.
Easiest is to have your passport config in a file of your own (i.e. where you setup all your passport strategies, etc), and that file exports the passport object after setting it up.
e.g.
/* in ./lib/passport.js */
module.exports = passport;
Then in some other file that needs it, you just require your passport file (code in there only gets called once, and the exported module is cached after that).
/* in some other file */
var passport = require('./lib/passport');
this has the advantage of simplicity, but a lot of folks feel (rightly so) that it's not quite as testable if you're doing unit tests, b/c you can't isolate the file under test as easily, etc.
so in that case, each module file will export a function which takes its dependencies in through a function. For example,
/* in your router file */
var router = require('express').Router();
var loginRoutes = function(passport){
router.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login'
}));
return router;
};
module.exports = loginRoutes;
then wherever you're pulling the routes into the app, that process just requires the route file and calls the function, passing it the passport instance. which looks like what you did in routes.js.

Related

Routes passport-local

I am trying to use passport-local to restrict access of a website.
For this I am using login_app for running passport-local, however this is in itself a route that is called from the main app.js.
While trying to route on a 2nd level (passport-files/routes) I find that my code is found, but the functions inside are not called.
This is my login_app code:
var express = require('express');
var router = express.Router();
var mongoose = require ('mongoose');
var flash = require('connect-flash');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var morgan = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
let app = express();
// pass passport for configuration
require('./passport-files/passport')(passport);
//For express application
app.use(morgan('dev'));
app.use(cookieParser()); // read cookies (needed for auth)
app.use(bodyParser()); // get information from html forms
//Initialize passport session
app.use(session({ secret: 'secret' })); // session secret
app.use(passport.initialize());
app.use(passport.session());
app.use(flash()); // use connect-flash for flash messages stored in session
// load our routes and pass in our app and fully configured passport
require('./passport-files/routes')(app, passport);
module.exports = router;
To simplify the question I am only putting the routes.js file here:
var express = require('express');
var router = express.Router();
let app = express();
module.exports = function (app, passport) {
//function views (app, passport) {
/* GET users listing. */
// HOME PAGE (with login links) ========
app.get('/', function(req, res) {
res.render('login-welcome', {});
});
// LOGIN ===============================
// show the login form
app.get('/log-in', function(req, res) {
res.render('login', { message: req.flash('loginMessage') });
});
// process the login form
app.post('/log-in', passport.authenticate('local-login', {
successRedirect : '/admin', // redirect to the secure profile section
failureRedirect : '/log-in', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
}));
// we will use route middleware to verify this (the isLoggedIn function)
app.get('/profile', isLoggedIn, function(req, res) {
res.render('profile', {
user : req.user // get the user out of session and pass to template
});
});
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
// route middleware to make sure a user is logged in
function isLoggedIn(req, res, next) {
// if user is authenticated in the session, carry on
if (req.isAuthenticated())
return next();
// if they aren't redirect them to the hosme page
res.redirect('/');
};
I pretty much built this using the example from scotch.io ( https://scotch.io/tutorials/easy-node-authentication-setup-and-local ), however I cannot get it to work this way.
If i write the routes directly into login_app, they are recognized, even though the authentification still does not work.
Do any of you have an idea how to solve this? Is more information required?
This may be the problem: in your login_app module you're exporting router, however you haven't actually defined any routes on router, they're all defined on a new instance of an app.
A simple example creating a router in one file, and exporting it to use in a main app.js file, would be like this:
/** app.js */
var express = require('express');
var app = express();
var myRoutes = require('./routes');
app.use(myRoutes);
app.listen(3000);
/** routes.js */
// instaniate a new router, add routes/middleware on it, and export it
var router = require('express').Router();
// define your routes and middleware here
// router.use( ... )
module.exports = router;
Another pattern, which I think the scotch.io tutorial is using, is to have the routes file export a function into which you pass your main app instance. Then the two files would look like this:
/** app.js */
var express = require('express');
var app = express();
require('./routes')(app); // pass your main `app` instance into the function
app.listen(3000);
/** routes.js */
module.export = function(app) {
// define all your routes and middleware here directly on the `app` that gets passed in
// app.use( ... )
}

Nodejs Express router.get('/') in users.js

I m still trying to learn NodeJs but I came across this path thing I encountered in Express. When I create an app using Express I noticed that in app.js I have these lines of code var index = require('./routes/index');
var users = require('./routes/users');
app.use('/', index);
app.use('/users', users);
And in users.js I already have configured
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
module.exports = router;
I don t really understand why is it in users.js router.get('/') instead of router.get('/users') as it is specified in app.js? Can someone explain a bit what s going on in this case?
As far as I understand in app.js it says whenever someone tries to access the specified route('/users') lets say localhost:3000/users in the browser, let the file required in users variable handle it.
If you are working with routes the express app is automatically . Here is an example from the express.js website:
In our router file we have:
var express = require('express')
var router = express.Router()
// middleware that is specific to this router
router.use(function timeLog (req, res, next) {
console.log('Time: ', Date.now())
next()
})
// define the home page route
router.get('/', function (req, res) {
res.send('Birds home page')
})
// define the about route
router.get('/about', function (req, res) {
res.send('About birds')
})
module.exports = router
Then in our main file were we have our server etc we load in the router:
var birds = require('./birds')
// ...
app.use('/birds', birds)
These routes in the router app are only accessed when there is a request to to /birds url. All the routes in the router are now automatically staring with /birds
So this code in the express router:
// im code in the birds router
router.get('/about', function (req, res) {
res.send('About birds')
})
Is only executed when someone makes a get request to the /birds/about url.
More information in the official express.js docs
I would just like to point out what I have learnt today after some frustration, and maybe somebody can elaborate as to why this happens. Anyway, if, like me, you want to use '/users' for all user routes or '/admin' for all administrator routes then, as WillemvanderVeen mentioned above, you need to add the following code to your main app.js file
var users = require('./routes/users')
app.use('/users', users)
However, one thing which was not mentioned is that the order with which you declare your 'app.use('/users', users)' in app.js is important. For example, you would have two route handling files as so:
/routes/index.js
const express = require('express');
const router = express.Router();
router.get('/', (req, res) => { res.render('index') });
/routes/users.js
const express = require('express'); const router = express.Router();
router.get('/', (req, res) => { res.send('users route') })
You would then require them in your main app.js file as so:
app.js
const express = require('express');
const app = express();
const index = require('./routes/index');
const users = require('./routes/users');
app.use('/', index);
app.use('/users', users);
and you would expect that when you hit the '/users' route that you would receive the res.send('users route') page.
This did not work for me, and I struggled to find any solution until recently, which is why I am now commenting to help you.
Instead, I swapped the app.use() declarations in app.js around like so and it worked:
app.js
const express = require('express');
const app = express();
const index = require('./routes/index');
const users = require('./routes/users');
app.use('/users', users);
app.use('/', index);
Now when I hit '/users' I see the 'users route' message. Hope this helped.
To answer your question though, when you configure the route handler in app.js as users, then you are requiring a router file (./routes/users) to handle all requests from that file and sending them to the URL /users first. So if you do the following:
/routes/users.js
router.get('/dashboard', (req, res) => {
// get user data based on id and render it
res.render('dashboard')
});
then whenever user is logged in and goes to dashboard, the URL will be /users/dashboard.

Pass object to router

I am new to Express.js but I want to learn it the right way. Hence I've started with using Peter Lyon's suggested code structure introduced here: https://github.com/focusaurus/express_code_structure . I am following a passport.js tutorial which requires me to pass the passport object to my router and I am stuck there
This is my index.js:
appCommon.head(app, passport)
// Load all Routers
app.use('/', require('./pages/router'))
app.use('/projects', require('./projects/router'))
app.use('/', require('./authentication/router'))(passport) // Pass passport to router
My authentication/router.js:
var express = require('express')
var join = require('path').join
var router = new express.Router()
// I removed the other functions
function processSignup (req, res) {
passport.authenticate('local-signup', {
successRedirect : '/profile', // redirect to the secure profile section
failureRedirect : '/signup', // redirect back to the signup page if there is an error
failureFlash : true // allow flash messages
})
}
router.use(express.static(join(__dirname, '../../wwwroot')))
router.get('/login', login)
router.get('/signup', signup)
router.post('/signup', processSignup)
router.get('/profile', isLoggedIn, profile)
router.get('/logout', logout)
module.exports = router
Questions:
Did I pass the passport object correctly to my router?
How can I add the passport object to my router so that the processSignup function is aware of it?
You should really not send any passport object to router. What you should do is use the Strategies in your main file like this:
// load passport strategies
const localStrategy = require('./server/passport')
passport.use('local-signup', localStrategy.Signup)
passport.use('local-login', localStrategy.Login)
After you use this strategy in passport you can use this strategy to authenticate right away in your any routes like below:
const passport = require('passport');
router.post('/login',
passport.authenticate('local-login', { successRedirect: '/',
failureRedirect: '/login',
failureFlash: true })
);

How to pass the configured passport object into the routes modules in Express4?

Since from Express 4 you're not supposed to do
require('./app/routes.js')(app, passport); // load our routes and pass in our app and fully configured passport
module.exports = function(app, passport) {
// =====================================
// FACEBOOK ROUTES =====================
// =====================================
// route for facebook authentication and login
app.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));
// handle the callback after facebook has authenticated the user
app.get('/auth/facebook/callback',
passport.authenticate('facebook', {
successRedirect : '/profile',
failureRedirect : '/'
}));
// route for logging out
app.get('/logout', function(req, res) {
req.logout();
res.redirect('/');
});
};
Instead, you're supposed to be using express.Route() function and
var routes = require('./app/routes.js');
app.use('/', routes);
How to pass the configured passport into the routes modules in Express 4?
The function export can still be used to pass the passport reference between modules. It would just create and return a Router rather than modifying the app directly.
var express = require('express');
module.exports = function(passport) {
var router = express.Router();
router.get('/auth/facebook', passport.authenticate('facebook', { scope : 'email' }));
// etc.
return router;
};
And, the app can then use it with:
var routes = require('./app/routes.js')(passport);
app.use('/', routes);

maintaining session on different routes

How do you maintain session between route.
I have 3 routes
var routes = require('./routes/index');
var users = require('./routes/users');
var question = require('./routes/question');
app.use('/', routes);
app.use('/users', users);
app.use('/question',question);
on top of the 3 js file is this:
var express = require('express');
var router = express.Router();
this created a new router thus losing the session i guess?
within users, i use passport to create a login system, by its default serializer the user information is saved under req.user but only accessible within users route.
I would like to use the session within routes(index) and question route. How do i solve this?
thanks,
As you mentioned that you have defined each request specific route in its separate file.
Then you donot need to define these line again in main file.
var express = require('express');
var router = express.Router();
app.use(passport.session());
function ensureAuthenticated(req, res, next) {
// passport.js provides this method req.isAuthenticated())
if (req.isAuthenticated())
return next();
else
// Return error content: res.jsonp(...) or redirect: res.redirect('/login')
}
Here, you can define your strategy to check routes. If it is authenticate then disclose user related information.
app.use('/', ensureAuthenticated, routes);

Resources