I'm working on a NodeJS project, and using Express as my routing framework.
I have a register form in my site, and a login form, both of which send requests to /users (/register and /login respectively). However, I would like to be able to have /users/:userID as routes to see profiles of different users, but of course, this routes imply that I have a session_id for every logged in user.
My question is, how can I use app.use('/users', checkForSessionId), without applying it to register and login?
This is where you need to use middleware
app.js
var users = require('./routes/user');
app.use('/users', users);
./routes/user.js
var express = require('express');
var router = express.Router();
function checkForSessionId(req, res, next){
//if no valid session
// return res.status(401).json("not authorised");
//else
next();
}
router.get('/:userId', checkForSessionId, function(req, res){
//this is a route which requires authentication
})
router.post('/register', function(req, res){
//authentication is not necessary
})
module.exports = router;
Related
I got stuck in Mozilla js tutorial and need help. Here are excerpts from 3 files:
a)
the 2 pieces from app.js file show where to find Router handlers and then where to present them (my guess)
//app.js
//the following 3 vars do sit in routes folder, code copy-pasted var 3 my addition
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var coolRouter = require('./routes/cool');
var app = express();
....
//the following 2 'use' work just fine, the third sends err 404, 'not found'
app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/users/cool', coolRouter);
b) part of the users.js sitting in routes folder:
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource');
});
c) part of the cool.js copied from the previous and sitting in routes folder:
/* GET cool text. */
router.get('/', function(req, res, next) {
res.send('you are cool, kid!');
});
I'd like to get it why it does not work.
The reason you cannot reach /users/cool is that your request is being cathed by the /users endpoint.
In order for your code to work as you intend it to do, you will have to place your routes like this:
app.use('/', indexRouter);
app.use('/users/cool', coolRouter);
app.use('/users', usersRouter);
With the /users/cool endpoint before the /users endpoint. That way, the request to /users/cool will not be catched by another endpoint.
I'm creating an app using node, express, and have a passport authorization middleware implemented for all routes-. I am following a highly modular approach to build my app. I try to exclude specific APIs from authentication when I include them above the authorization middleware. But when I include app.use('/', require('./api/search/index')); above the authorization middleware, APIs beneath stop working.
Criticism and suggestion are all welcome for this approach and what can I do to resolve this problem.
I don't want to include route middleware in each route like this
route.get('/example', auth.middleware(), function (req, res) {
})
Below is my app approach with single authorization middleware for all routes
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
var auth = require("./auth.js")();
app.use(auth.initialize());
//Excluding the search API from Authentication,
app.use('/', require('./api/search/index'));
//Middleware for all APIs and require Auth headers for authrization access
app.use(auth.authenticate(), function (req, res, next) {
if (req.headers.authorization && req.user) {
var parted = req.headers.authorization.split(' ');
if (parted.length === 2) {
console.log(req.user);
next();
} else {
return res.status(403).send({
success: false,
msg: 'Unauthorized.'
});
}
} else {
return res.status(503).send({
success: false,
msg: 'Bad Request'
});
}
});
//Join routers
app.use('/', require('./api/users/index'));
app.use('/', require('./api/product/index'))
app.use('/', require('./api/company/index'))
There are a million ways you can do this. What you can do is this:
app.use('/', require('./api/search/index'));
app.use('/', auth.authenticate(), require('./api/users/index'));
app.use('/', auth.authenticate(), require('./api/product/index'))
app.use('/', auth.authenticate(), require('./api/company/index'))
This way, the auth.authenticate() middleware will be applied to every child route you are requiring. And you leave the index without anything. This gives you a more granular control of where you apply the auth middleware, without having to apply it to every single route. You can take this to another level and group several routes inside a /admin/ and apply the middleware only once. Your imagination is the limit.
You can block your routes together using express.Router. For instance, you could have a route called "/api/secure" and then create a router for that route and group all secure routes there. and then have another for unsecured routes'
Express Router Docs
I am new to Node.js and express framework. I am getting an error when I am trying to go to the signuplogin route from my homepage route. I have also tried all the similar questions in the stackoveflow, but none of them have worked for me, so I thought of posting my own.
This is my app.js
var homepage = require('./routes/homepage');
var signupLogin = require('./routes/signuplogin');
var app = express();
app.use("/", homepage);
app.use("/signup-login", signupLogin);
This is my homepage.js in routes directory
var express = require('express');
var homepageRouter = express.Router();
/* GET Homepage. */
homepageRouter.get("/", function(req, res, next) {
res.render('../views/homepage/homepage.hbs');
});
module.exports = homepageRouter;
This is my signup-login.js in routes directory
var express = require('express');
var signupLoginRouter = express.Router();
/* GET Signup Login Page. */
signupLoginRouter.get("/signup-login", function(req, res, next) {
res.send('respond with a resource');
});
module.exports = signupLoginRouter;
Well my "/" route works perfectly but it says 404 when I try to access "/signup-login" route.
I also changed the route to "/signuplogin" because I thought maybe it doesn't except the "-" character in the route. But that didn't work as well. Any solution/advice?
You have done a mistake in your signup-login.js file. Correct the code with this -
/* GET Signup Login Page. */
signupLoginRouter.get("/", function(req, res, next) {
res.send('respond with a resource');
});
As per your code the actual url of signup page becomes to "/signup-login/signup-login"
You don't need to add the singup-login url path again in your page. That is already referenced in your main router.
I used express generator and am confused as to why I cannot use the users.js routes file for my login routes.
I created the POST route below and if I leave it in app.js it works fine. However, if I move it into users.js and try to use
app.use('/login', users)
where users is :
var users = require('./routes/users');
from app.js to reference it, I get errors that there is no post route to /login. Why does this happen ?
app.post('/login', function(req,res) {
var user = req.body.user;
db.User
.authenticate(user.email, user.password)
.then(function (user) {
req.login(user);
res.redirect("/"); // redirect to user profile
});
});
You're mounting a router that handles /login to the path /login.
This results in the URL /login/login.
You probably want to make the inner router handle /.
I have a ExpressJS app that is using Passportjs to authenticate with Facebook and everything is working as expected exception for one issue.
I have vehicle.js under /routes/ which contains some routes (router.gets and router.posts) that need authentication and some that don't. If user is logged in then every request handled by vehicle.js causes User de-serialization which is a Mongoose lookup. How can I avoid these unnecessary Mongoose lookups when request is made to a router.get and/or router.post that do not need authentication?
I have already looked up this SO question and it does not address my problem (I have declared static resources above passport, so they are not authenticated).
Passport configs in app.js are shown below:
// Configuring Passport
var passport = require('passport');
var expressSession = require('express-session');
app.use(expressSession({secret: 'thisIsSecret'}));
app.use(passport.initialize());
app.use(passport.session());
// Using the flash middleware provided by connect-flash to store messages in session
// and displaying in templates
var flash = require('connect-flash');
app.use(flash());
// Initialize Passport
var initPassport = require('./passport/init');
initPassport(passport);
//passing passport object could be the reason why all requested that are
//mapped in vehicle cause user de-serialization. Not sure if there is any
//alternative approach than following line that passes passport??
var vehicle = require('./routes/vehicle')(passport);
The following isAuthenticated is in vehicle.js
var isAuthenticated = function (req, res, next) {
if (req.isAuthenticated())
return next();
// if the user is not authenticated then redirect him to the login page
res.redirect('/vehicle/api/login');
}
Followed by a series of routes that handle logging in, logging out, as well as some actions on vehicle.
module.exports = function(passport) {
router.get('/api/login', function(req, res) {
res.render('vehicle/login', { message: req.flash('message') });
});
router.post('/api/login', passport.authenticate('login', {
successRedirect: '/vehicle/api/list/mine',
failureRedirect: '/vehicle/api/list',
failureFlash : true
}));
...
...
...
router.post('/api/upload', isAuthenticated, function(req, res) {
//this route needs to be authenticated, so it works fine,
//deserialization done, mongoose lookup, no problem
});
router.get('/api/image/:vehicleId/:filename', function(req,res) {
//this route does not need authentication, but causes User
//de-serialization and Mongoose lookup
});
return router;
}
Is it because of the following line that every request to vehicle.js causes User de-serialization when a user is logged in?
var vehicle = require('./routes/vehicle')(passport);
One way to avoid such unnecessary de-serialization would be to separate routes that do not need authentication from vehicle.js to a different file and do not pass that passport object to that file (as it is passed to vehicle.js in app.js). I don't know if that is the correct way to resolve this issue.
You can wrap the passport middleware inside a custom middleware that only invokes it for your specified routes. So Instead of:
app.use(passport.session());
you could:
app.use(function(req, res, next){
if(req.url.match('api/image'))
next(); // do not invoke passport
else
passport.session()(req, res, next)
// same as doing == app.use(passport.session())
});
If you use passport.session() middleware, deserialize will happen for every route:
https://github.com/jaredhanson/passport/blob/33075756a626999c6e2efc872b055e45ae434053/lib/strategies/session.js#L53-L69
The solution would be to add it only to ones which use passport.