next() not working in Express 4 - node.js

this is my app.js
function requireLogin(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.redirect("/");
}
}
/**
* Routes
*/
var index = require('./routes/index');
var dashboard = require('./routes/dashboard');
app.use('/', index);
app.use('/dashboard', requireLogin, dashboard);
routes/dashboard.js
var express = require('express');
var router = express.Router();
router.route('/')
.get(function (req, res, next) {
res.render('dashboard/index', {});
});
module.exports = router;
After doing the login I am directed to the route /dashboard, but I get a status 404.
If I try to remove the function requireLogin, the route /dashboard is visible and working.
Why?
I did some tests, and I saw that the problem is next().
For the login I used passport is working well.

If you still haven't figured out you can put return next() instead of next().
So this:
function requireLogin(req, res, next) {
if (req.isAuthenticated()) {
next();
} else {
res.redirect("/");
}
}
Should become this:
function requireLogin(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.redirect("/");
}
}
Hope I helped!

Actually I had a very similar issue, for me it wasn't anything to do with the middleware that was handling authentication, it was the way my routes were set up.
I think you are trying to receive GET requests on a route you want to POST credentials to in dashboard.js:
router.route('/')
.get(function (req, res, next) {
res.render('dashboard/index', {});
});
should be:
router.route('/')
.post(function (req, res, next) {
res.render('dashboard/index', {});
});
since you are posting credentials to that route.

Related

Node.js - Why checkAuthenticated middleware function cannot be exported from another file?

I have a node.js app that uses express, handlebars and passport.js for authentication. I have setup a routes folder for login
app.js
app.use('/login', require('./routes/login'));
routes/ login.js
const checkAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return res.redirect("/");
}
next();
};
router.get("/", checkAuthenticated, (req, res) => {
res.render("login");
});
module.exports = router;
This works fine.
However, if I put the checkAuthenticated middleware function in app.js then export and require it in login.js I get this error.
router.get() requires callback
app.js
app.use('/login', require('./routes/login.js'));
const checkAuthenticated = (req, res, next) => {
if (req.isAuthenticated()) {
return res.redirect("/");
}
next();
};
module.exports = { checkAuthenticated };
routes/login.js
const { checkAuthenticated } = require('../app.js');
router.get("/", checkAuthenticated, (req, res) => {
res.render("login");
});
module.exports = router;
Why doesn't it work when this function is required from another file like a normal function? I am trying to avoid duplication as I need exact same function for routes/register.js

res.locals variable empty or out of scope?

so when I log into my website and navigate within the same url (ex: localhost/private/xxxx), the res.locals.user returns an object.
When I go out of the range (ex: localhost/xxxx), res.locals.user is empty.
/ app.js
...
app.use(passport.session());
app.use(require('./controllers'));
...
/ controllers / index.js
router.use('/private', require('./member.js'));
router.use('/admin', require('./admin.js'));
/* Some basic routes. */
router.get('/', function(req, res, next) {
res.render('index', { ... });
});
After loggin in res.locals.user is still empty here
/ controllers / member.js
router.use(function isMember(req, res, next) {
if(req.isAuthenticated()) {
res.locals.user = req.user;
return next();
}
req.flash('error', 'WHY YOU LITTLE!');
res.redirect('/login');
});
router.get('/', function(req, res, next) {
res.redirect('/private/index');
});
router.get('/something', function(req, res, next) {
res.redirect('/private/somehting');
});
router.get('/darkside', function(req, res, next) {
res.redirect('/private/darkside');
});
res.locals.user correctly returns the user, whether I navigate to /private, /private/something or /private/darkside
Is it cause I use a middleware route when using router.use('/private', require('./member.js')); ? How do I fix this?
res.locals is an object passed to the rendering engine of your app. You can set the user details by req.session.user = user in passport authentication strategy.So that you can access the user from any of your route.
At the end I simply had to add
router.use(function (req, res, next) {
if(req.isAuthenticated()) {
res.locals.user = req.user;
}
return next();
});
before all my routes and remove res.locals.user = req.user; from the member.js file
So it would give me this:
/ controllers / index.js
router.use(function (req, res, next) {
if(req.isAuthenticated()) {
res.locals.user = req.user;
}
return next();
});
router.use('/private', require('./member.js'));
router.use('/admin', require('./admin.js'));
/* Some basic routes. */
router.get('/', function(req, res, next) {
res.render('index', { ... });
});

How to pass multiple parameters from controller in node.js express

I am working with Passport, and I need to pass multiple parameters through to from my controller to my router. Basically it only passes the first one.
I want to get
app.get('/auth/steam', controllers.auth.authenticate);
to result in
app.get('/auth/steam', passport.authenticate('steam'), function(req, res) { res.render('index') };);
Right now it only loads the 1st parameter.
My controller looks like this
exports.authenticate =
passport.authenticate('steam'),
function(req, res) {
res.render('index');
};
How would I do this?
EDIT: I want to only be able to call it with controllers.auth.authenticate, not in an array like: controllers.auth.authenticate[0]!
Warning NOT tested.
You can wrap all inside function
exports.authenticate = function(req, res, next) {
passport.authenticate('steam', function(err, user, info) {
if (err) { return next(err); }
if (!user) { return res.redirect('/auth/steam'); }
res.render("index");
});
}
Or you can use router and protect ALL verbs (get, post, etc)
var express = require('express');
var router = express.Router();
router.use(function (req, res, next) {
passport.authenticate('steam');
});
router.get('/', function(req, res, next) {
res.render("index");
});
module.exports = router;
And use router on the app
var ctrl = require("yourModuleName");
app.use('/auth/steam', ctrl); // app.use NOT app.get
Other alternative is to protect only the get
var express = require('express');
var router = express.Router();
router.get('/', passport.authenticate('steam'), function(req, res, next) {
res.render("index");
});
module.exports = router;
var ctrl = require("yourModuleName");
app.use('/auth/steam', ctrl); // app.use NOT app.get
See Express routing page

how to group api in express

Here is the example:
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
//code
});
app.post('/user/register', function(req, res) {
//code
})
app.put('/user/register', validateToken, function(req, res) {
//code
})
app.delete('/user/delete', validateToken, function(req, res) {
//code
})
If I have 10 api that need validToken, I should add validToken middleware 10 times, like:
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
....
app.method('......', validateToken, function(req, res) {
//code
})
app.method('......', validateToken, function(req, res) {
//code
})
How can I group api by using the same middleware?
Here's how to re-use the same callback function for multiple routes (like middleware):
var app = require('express')();
function validateToken(req, res, next) {
// Do something with request here
next();
};
app.get('/user/login', function(req, res) {
// code
});
app.post('/user/register', function(req, res) {
// code
});
// Be sure to specify the 'next' object when using more than one callback function.
app.put('/user/register', validateToken, function(req, res, next) {
// code
next();
});
app.delete('/user/delete', validateToken, function(req, res, next) {
// code
next();
});
Also, you can replace app.METHOD (e.g. .post, .get, .put, etc.) with app.all and your callback will be executed for any request type.
Just wrong, so do not put into mass participation of the (Google translated from: 刚才看错了,改成这样就不用放进传参了)
var group = {url:true,url:true,url:true};
app.use(function(req,res,next){
if(group[req.url]){
// Do something with request here
next();
} else {
next();
}
})

How to call Connect middleware directly?

I have a express route like this:
app.get('/', auth.authOrDie, function(req, res) {
res.send();
});
where authOrDie function is defined like that (in my auth.js module):
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
res.send(403);
}
});
Now, when the user is not authenticated, I would like to verify if the http request has a Authorization (Basic) header. To do that, I would like to use the great connect middleware basicAuth().
As you know, Express is built on top of Connect, so I can use express.basicAuth.
The basicAuth is generally used like that:
app.get('/', express.basicAuth(function(username, password) {
// username && password verification...
}), function(req, res) {
res.send();
});
But, I would like to use it in my authOrDie function like that:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else if {
// express.basicAuth ??? ******
} else {
res.send(403);
}
});
****** How can I call the basicAuth function with the good parameters (req ? res ? next ? ...).
Thanks.
Calling the express.basicAuth function returns the middleware function to call, so you'd invoke it directly like this:
exports.authOrDie = function(req, res, next) {
if (req.isAuthenticated()) {
return next();
} else {
return express.basicAuth(function(username, password) {
// username && password verification...
})(req, res, next);
}
});

Resources