How to show logged on username in NodeJS/ExpressJS/Passport? - javascript

I want to display the username in case the user is logged in (function 3). Initially, I only had function 1. I've changed function 1 into function 2 in order to display the username of the logged in user. I am not sure if this is the right way to do this, because I don't know if I need parameters res and next, and function next(). Any idea?
I am using NodeJS, ExpressJS and Passport
1.
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next()
} else {
res.redirect('/login')
}
}
2.
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return true
}
return false
}
3.
router.get('/', function(req, res) {
if (isLoggedIn) {
res.render('index', {
username: req.user.username
})
} else {
res.render('index')
}
})

You are pretty much doing the right but calling the method isLoggedIn like a variable. I have corrected the same below.
2.
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return true;
}
return false;
}
3.
router.get('/', function(req, res, next) {
if (isLoggedIn(req, res, next)) {
res.render('index', {
username: req.user.username
});
} else {
res.render('index');
}
});
Also, you can refactor the isLoggedIn method as below.
function isLoggedIn(req, res, next) {
return req.isAuthenticated();
}

Related

How to pass a parameter to middleware function in Express JS?

// state edit route
app.get("/map/:symbol/edit", isLoggedIn, function(req, res){
State.findOne({symbol: req.params.symbol}, function(err, state){
if(err){
console.log(err);
} else
{
res.render("edit", {state: state});
}
});
});
In the above code snippet, isLoggedIn is the middleware function to check for authentication. Its definition is given below:
// middleware function
function isLoggedIn(req, res, next){
if(req.isAuthenticated()){
return next();
}
res.redirect("/admin");
}
So, the question is, how to pass a parameter like a string, an integer or a path variable to the middleware function so that it can be used in the routing url ?
I had the same requirement and this approach works for me.
Middleware file validate.js
exports.grantAccess = function(action, resource){
return async (req, res, next) => {
try {
const permission = roles.can(req.user.role)[action](resource);
// Do something
next();
}
catch (error) {
next(error)
}
}
}
Use of middleware in route file. grantAccess('readAny', 'user')
router.get("/",grantAccess('readAny', 'user'), async (req,res)=>{
// Do something
});
Follow this approach, it might do the job for you
app.use(function(req, res, next){
console.log(req);
this.req = req;
// assign value like this
this.req.body.custom_data = ['zz', 'aaa', ....];
next();
});
app.get("/map/:symbol/edit", isLoggedIn, function(req, res){
State.findOne({symbol: req.params.symbol}, function(err, state){
if(err){
console.log(err);
} else {
res.render("edit", {state: state});
}
});
});
function isLoggedIn(req, res, next){
console.log(req.body);
if(req.isAuthenticated()){
return next();
}
res.redirect("/admin");
}
This is the way I'm using it, I take a little bit of Hardik Raval answer.
helpers.validateRole = (roles) => {
return async (req, res, next) => {
try {
const authHeader = req.headers['authorization']
const token = authHeader && authHeader.split(' ')[0]
if (token == null) return res.json({error:true, msg: "Unauthorized"})
const user = jwt.decode(token)
let isValid = false
roles.map((r,i)=>{
if (r === user.role){
isValid = true
}
})
if (isValid){
// User role is valid
next();
}else{
// User role is not valid
util.returnError("Unauthorized", res);
}
}
catch (error) {
next(error)
}
}
}
And I called like this.
router.get( "/requirements/list_of_requirements/:page/:rows", isAuthenticated, validateRole([6]), async (req, res) => {
//* All the logic
})

Req.isAuthenticated turns to false

When I log in I'm authenticated but when I switch to another page req.isAuthenticated returns false and I'm on login panel. The second thing is when I log in I keep getting an error "can't set headers after they are sent". Here is my code:
const isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
return res.end();
} else {
return res.redirect("/login");
}
}
module.exports = (app, passport) => {
app.post("/login", (req, res, next) => {
passport.authenticate("local-login",
(err, user, info) => {
if(!user) {
res.render("index", { message: "Wrong password or login!" })
} else {
req.login(user, (error) => {
if (error) return next(error);
console.log("AUTH: ", req.isAuthenticated()) <--- RETURNS TRUE
return res.render("map", { name: user.name });
});
}
})(req, res, next);
});
app.get("/", (req, res) => {
return res.render("index"); // load the index file
})
app.get("/login", (req, res) => {
return res.render("index"); // load the index file
})
app.get("/map", isLoggedIn, (req, res) => {
return res.render("map");
});
app.get("/vehicles", isLoggedIn, (req, res) => {
return
});
app.get("/settings", isLoggedIn, (req, res) => {
res.render("settings");
});
app.get("/logout", (req, res) => {
req.logout();
res.redirect("/");
});
};
Login page will of course give you req.isAuthenticated true because you are just authenticated by passport middleware.
Passport will return req.isAuthenticated true until you are not getting logged out and it will set req.isAuthenticated false when you hit /logout route
So maintaining the state of user you have to use sessions for storing state of
application.
find below link : https://www.npmjs.com/package/express-session
you are getting "can't set headers after they are sent". because you are returning response twice. one that is after req.isAuthenticated() getting turn true and second is like you are again rendering a map page.
so instead of return res.end() you should have to use next()
const isLoggedIn = (req, res, next) => {
if (req.isAuthenticated()) {
req.session.isAuthenticated = true;
res.locals.isAuthenticated = true;
res.locals.user =req.user;
next(); //If you are authenticated, run the next
} else {
return res.redirect("/login");
}
}

Providing Custom Params In Express Middleware

I am having a problem with my Node.js app. In short I want to pass custom parameters into my middleware function other than just req, res, and next.
Middleware file:
var DB = require('./DB.js');
function requirePermissions(e) {
console.log('nope')
}
module.exports = requirePermissions;
Route:
router.post('/posts', requirePermissions('post_creation'), function(req, res) {
var o = req.body,
title = o.post.title,
content = o.post.content;
res.send('made it');
});
I have confirmed that using function requirePermissions(req, res, next) {} will work, but I do not understand how to include my own parameters.
Your function requirePermissions should return another function which will be the actual middleware:
function requirePermissions(e) {
if (e === 'post_creation') {
return function(req, res, next) {
// the actual middleware
}
} else if (e === 'something_else') {
return function(req, res, next) {
// do something else
}
}
}
You can also do it like that:
function requirePermissions(e) {
return function(req, res, next) {
if ('session' in req) {
if (e === 'post_creation') {
// do something
} else if (e === 'something_else') {
// do something else
}
}
}
}
You can just create an anonymous function for your middleware that lets you call your actual function with some additional arguments:
router.post('/posts', function(req, res, next) {
requirePermissions('post_creation', req, res, next);
}, function(req, res) {
var o = req.body,
title = o.post.title,
content = o.post.content;
res.send('made it');
});
Or, you can use .bind() to preprend arguments:
router.post('/posts', requirePermissions.bind('post_creation'), function(req, res) {
var o = req.body,
title = o.post.title,
content = o.post.content;
res.send('made it');
});
This will call your requirePermissions() functions with four arguments like this:
requirePermissions('post_creation', req, res, next)

Have pointer function receive args from .get() closure?

Is there a way to use facebookResponse as a pointer function, rather than using a anon function, and have it access req, res, next? I thought about using bind but I don't know how I would bind the .get() method of the route. I didn't have success with passport.authenticate('facebook',facebookResponse.call(this, req, res, next).
auth.route('/auth/facebook/callback')
.get(function(req, res, next) {
passport.authenticate('facebook', facebookResponse);
});
function facebookResponse(err, userDoc, info) {
if (err) { return next(err); }
// I don't think !userDoc will ever happen because of mongo upsert
if (!userDoc) { return res.redirect('/login'); }
req.logIn(userDoc, function(err) {
if (err) { return next(err); }
return res.redirect('http://localhost:9000/users');
});
}
One way would be to use a function to return a function:
auth.route('/auth/facebook/callback')
.get(function(req, res, next) {
passport.authenticate('facebook', facebookResponse(req, res, next));
});
function facebookResponse(req, res, next) {
return function(err, userDoc, info) {
if (err) { return next(err); }
// I don't think !userDoc will ever happen because of mongo upsert
if (!userDoc) { return res.redirect('/login'); }
req.logIn(userDoc, function(err) {
if (err) { return next(err); }
return res.redirect('http://localhost:9000/users');
});
}
}
Here your inner function has access to the outer functions parameters (req, res, next) in a closure.

I've built an express js app. When I load a page I always have to refresh for varibles to display?

Hope you can help me. I have searched for an answer but haven't been able to find one.
I have built an app in Express.js that has a simple form in jade. It should display "Yes" if the database is connected.
The page will load and display nothing. If I then Ctrl-R or refresh the value I was expecting will appear correctly.
How do I make it so it automatically appears without refreshing..?
Cheers and thank you,
Matt
index.jade
p Connected to DB?:
if locals.connected
p= connected
index.js (routed to via app.js -> routes.js -> index.js
Var connected;
function listCollections() {
mongoose.connection.on('open', function () {
connected = "Yes";
});
}
exports.init = function(req, res, next){
listCollections();
res.render('./index', {
connected:connected
});
}
};
Routes.js
function ensureAuthenticated(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.set('X-Auth-Required', 'true');
req.session.returnUrl = req.originalUrl;
res.redirect('/login/');
}
function ensureAdmin(req, res, next) {
if (req.user.canPlayRoleOf('admin')) {
return next();
}
res.redirect('/');
}
function ensureAccount(req, res, next) {
if (req.user.canPlayRoleOf('account')) {
if (req.app.config.requireAccountVerification) {
if (req.user.roles.account.isVerified !== 'yes' && !/^\/account\/verification\//.test(req.url)) {
return res.redirect('/account/verification/');
}
}
return next();
}
res.redirect('/');
}
exports = module.exports = function(app, passport) {
app.all('/*', ensureAuthenticated);
app.all('/*', ensureAccount);
//product
app.get('/', require('./views/index').init);
app.post('/', require('./views/index').init);
};
Since its asynchronous, the page gets render before your connection gets established. you should do something like this.
function listCollections(callback) {
mongoose.connection.on('open', function () {
callback("Yes"); // render callback gets invoke after connection
});
}
exports.init = function(req, res, next){
listCollections(function(connected){ // passing render as callback
res.render('./index', {
connected:connected
});
});
}

Categories

Resources