render() - how it loads controllers? - node.js

I give 401 Uanthourised acces header with
module.exports = function() {
return function(req, res, next) {
if (!req.isAuthenticated()) {
res.status(401);
console.log('Unauthorized');
res.render('login.html', { csrfToken: req.csrfToken() });
return;
}
next();
};
};
Now login.html is a view handled by completly different controller:
var passport = require('passport');
var config = require(__dirname + '/../lib/config');
module.exports = function (router) {
router.get('/', function (req, res) {
// Error flash messages
var errorFlash = req.flash('error');
if (errorFlash && errorFlash.length) {
res.locals.error = errorFlash;
}
res.render('login.html', { csrfToken: req.csrfToken() });
});
router.post('/',
passport.authenticate('local', {
failureRedirect: '/login/',
failureFlash: true
}),
function(req, res) {
res.cookie(config.cookie.name, req.user.email, { signed: true, maxAge: 1234 });
res.redirect('/');
}
);
};
My concern is how I can be sure what part of login controller fires up? render('index.html') somehow hooks up to router.post() in index controller and login form is handler as usual. How that can be?

If you ever have any doubt which function is being called then a good approach is to (temporarily) add a console.log() within that function. I will often do something like:
console.log('filename.js - functionname() called with args: [%s] [%s]', arg1, arg2);
And then watch the log for information about what fired off and what variables you're trying to watch.
It could be that you need to redirect rather than render in your 401-related code.
res.redirect('/login');
(Edited)

The controller will always go to "index" if you did not provide any method.
The reason that it is a "POST" is probably that you are trying to send a form to the index page.
If you just request the index page. for example "(url)/login/index" or just "(url)/login" then it would be a "GET" request, but what are you trying to tell, I don't understand your question completely

Related

Nodejs Sync functions?

I am trying to set it to true and only then redirect to another page. However I get redirected first and then it's set to true..
Code:
exports.logIn= function(req, res, next) {
req.session.loggedIn = true;
res.redirect("/home");
};
You can achieve this using res.locals
exports.logIn= function(req, res, next) {
//AUTHENTICATE
res.locals.loggedIn = true;
res.redirect("/home");
};
Then on '/home' route you can check the user is logged in or not by reading res.locals.loggedIn
if(res.locals.loggedIn){
// DO SOMETHING
} else {
//REDIRECT TO LOGIN
}

Execute a function before rendering express get router NodeJS

I want to execute a function each time when the express router is called.
I know I could have placed the function simply inside the app.get function, but I want to call the same function multiple times.
Here is my router.js file:
var Setting = require('../models/setting');
module.exports = function(app, passport) {
// =====================================
// HOME PAGE (with login links) ========
// =====================================
app.get('/', function(req, res) {
Setting.findOne(function(err, setting) {
if (err)
throw err;
// console.log(setting);
res.render('index', { title: 'eduBird | Reach the glory', setting: setting }); // load the index file
});
});
// =====================================
// LOGIN ===============================
// =====================================
// show the login form
app.get('/login', sabSettings, function(req, res) {
// render the page and pass in any flash data if it exists
res.render('login', {
message: req.flash('loginMessage'),
errors: req.flash('error'),
title: 'Login | eduBird',
setting: setting
});
});
// process the login form
app.post('/login', passport.authenticate('local-login', {
successRedirect: '/profile',
failureRedirect: '/login',
failureFlash: true
}));
// =====================================
// SIGNUP ==============================
// =====================================
// show the signup form
app.get('/signup', function(req, res) {
// render the page and pass in any flash data if it exists
res.render('signup', {
message: req.flash('signupMessage'),
errors: req.flash('error'),
title: 'Register | eduBird',
setting: req.setting
});
});
// process the signup form
app.post('/signup', passport.authenticate('local-signup', {
successRedirect: '/profile',
failureRedirect: '/signup',
failureFlash: true
}));
// app.post('/signup', function(req, res) {
// console.log(req);
// });
// =====================================
// PROFILE SECTION =====================
// =====================================
// we will want this protected so you have to be logged in to visit
// we will use route middleware to verify this (the isLoggedIn function)
app.get('/profile', isLoggedIn, sabSettings, function(req, res) {
res.render('profile', {
user: req.user, // get the user out of session and pass to template
title: req.user.local.name + "'s profile | eduBird",
setting: req.setting
});
});
// =====================================
// LOGOUT ==============================
// =====================================
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 home page
res.redirect('/login');
};
function sabSettings(next) {
Setting.findOne(function(err, setting) {
if (err)
throw err;
console.log('sabSetting function executed');
console.log(setting);
console.log('~~~~~~~~~~~');
// return setting;
return next(setting);
});
};
Here I had used an example of isLoggedIn which is executing fine, but the same is not able to work for sabSettings() which would pass all settings config from database to, my /login, /signup, /profile and/or / all the routes.
The console.log(setting) is returning all the data to my console, but I am getting an error stating:
throw er; // Unhandled 'error' event
^
TypeError: next is not a function
at C:\Users\animeshweb\Desktop\projects\eb-v2\routes\routes.js:106:16
You can see that I had embedded a function in app.get('/') for getting the same, but I want this function to be executed wherever I want, so I want a separate function for that.
Update
I update my routes.js as requested:
function sabSettings(req, res, next) {
Setting.findOne(function(err, setting) {
if (err)
next(err);
console.log('sabSetting function executed');
console.log(setting);
console.log('~~~~~~~~~~~');
req.setting = setting;
next();
});
};
I had also made Setting = require(myModelURL) above, which is working fine fo route.get'/'.
*This is my view/layout.pug file`
link(rel='icon', type='image/png', href=setting.logo.logo16 sizes='16x16')
link(rel='icon', type='image/png', href=setting.logo.logo32 sizes='32x32')
link(rel='icon', type='image/png', href=setting.logo.logo128 sizes='128x128')
The same is working fine in adminlayout0.pug
Thanks.
You've declared sabSettings wrong. Middleware is passed three arguments so your declaration should be like this:
function sabSetting(req, res, next) {
// function logic here
}
Since the argument you named next was in the wrong position, it was not a function when you tried to call it.
And, I don't know why you are trying to do return next(setting). That will tell Express that you're reporting an error in the request. If you're trying to put the setting value somewhere that the rest of the request handlers can use it, then you probably want to put it on the req object such as:
req.setting = setting; // put setting on the req object for other code to use
next(); // continue routing
In addition, you should never do a throw err inside a middleware function. That simply won't do anything useful and your request will probably never get finished. Instead, you should handle the error when you get it. You may either branch to some alternate strategy within the middleware when you get an error or you may simply returned a failed request with either next(err) or by doing res.status(500).send(...).
You will then need to change your res.render() to this:
res.render('index', { title: 'eduBird | Reach the glory', setting: req.setting });
The setting variable is now stored on the req object so that's where you need to refer to it.
Change it everywhere you are referring to setting.

Automatically redirect logged in users nodejs passport.js

Currently using node.js, express & passport.js to create a custom website/application.
Having followed several guides, I have a functioning login/logout system with authentication. However, should a user revisit and their session is still active, it doesn't redirect them to the 'dashboard'.
Current root route:
/* GET login page. */
router.get('/',function(req, res) {
// Display the Login page with any flash message, if any
res.render('index', { message: req.flash('message') });
});
I am making use of the isAuthenticated function, as below:
var isAuthenticated = function (req, res, next) {
if (req.isAuthenticated())
return next();
res.redirect('/');
}
How do I get it to automatically redirect users with an existing session? Any pointers most welcome!
Ok, I figured it out. In the / route, I queried whether req.user was set.
/* GET login page. */
router.get('/',function(req, res) {
if(req.user){
res.redirect("/dashboard");
}else{
// Display the Login page with any flash message, if any
res.render('index', { message: req.flash('message') });
}
});
You can attach a middleware with "/" endpoint something like this.
router.get('/', sessionValidate, function(req, res, next) {
res.render('login');
});
Where sessionValidate looks something like this :
function sessionValidate(req,res,next){
console.log(req.user,"i am here");
users.findById(req.user,function(err, user) {
if(user!=null){
req.session.user = user;
res.locals.user=user;
res.redirect("/home")
}
else {
next();
}
});
}

How to know if user is logged in with passport.js?

I've been reading passport.js info and samples for two days, but I'm not sure after that I did all the process of authenticating.
How do I know if I'm logged in, for example, I'll have a navigation bar with a login or logout button, is there some variable like code below?
if (login)
<button>logout</button>
else
<button>login</button>
If user is logged in, passport.js will create user object in req for every request in express.js, which you can check for existence in any middleware:
if (req.user) {
// logged in
} else {
// not logged in
}
You can create simple express.js middleware for that, that will check if user is logged in, and if not - will redirect to /login page:
function loggedIn(req, res, next) {
if (req.user) {
next();
} else {
res.redirect('/login');
}
}
And use it:
app.get('/orders', loggedIn, function(req, res, next) {
// req.user - will exist
// load user orders and render them
});
If you would like to use it in your templates as your code sample seems to indicate you can create some middleware such as this:
app.use(function (req, res, next) {
res.locals.login = req.isAuthenticated();
next();
});
Place that code somewhere after you have setup passport.
And then use it in your template (swig example)
{% if login %}
<button>logout</button>
{% else %}
<button>login</button>
{% endif %}
It is not explicitly documented but there is a isAuthenticated() method which is inserted into req by passport.
Can be used as follows,
req.isAuthenticated() // returns true if auth, false if not
// auth.js
module.exports = {
ensureAuthenticated: (req, res, next) => {
if (req.isAuthenticated()) {
return next()
}
res.redirect('/login') // if not auth
},
forwardAuthenticated: (req, res, next) => {
if (!req.isAuthenticated()) {
return next()
}
res.redirect('/dashboard'); // if auth
}
}
// app.js
app.get('/dashboard', ensureAuthenticated, (req, res) => res.render('dashboard'))
app.get('/login', forwardAuthenticated, (req, res) => res.render('login'))
app.get('/register', forwardAuthenticated, (req, res) => res.render('register'))
I was searching such solution and came across this page. Question is how to check login status on client side.
After logging I hide the Login button and show the logout button. On page refresh I again see the login button instead of logout button. The only solution is to save an item in sessionStorage if you are using session (and localStorage if you are using JWT). Delete this item when you logout.
Then in every page load check this sessionStorage item and do accordingly.
if (sessionStorage.getItem('status')) {
$("#btnlogout").show();
$("#btnlogin").hide();
// or what ever you want to do
} else {
$("#btnlogout").hide();
$("#btnlogin").show();
}
function Login() {
var data = {
username: $("#myModal #usr").val(),
password: $("#myModal #pw").val()
};
$.ajax({
type: 'POST',
url: '/login',
contentType: 'application/JSON; charset=utf-8',
data: JSON.stringify(data),
success: funcSuccess,
error: funcFail
});
function funcSuccess(res) {
sessionStorage.setItem('status', 'loggedIn');
$("#btnlogout").show();
$("#btnlogin").hide();
}
function funcFail() { $("#pp").text('Login Failed'); };
};
function Logout() {
$.ajax({
type: 'GET',
url: '/logout',
contentType: 'application/JSON; charset=utf-8',
success: funcSuccess,
error: funcFail,
});
function funcSuccess(res) {
$("#btnlogout").hide();
$("#btnlogin").show();
sessionStorage.removeItem("status");
};
function funcFail() { alert('Login method Failed'); };
};
use below code inside app.get() or router.get()
router.get('/edit/:id', (req, res)=>{
if(req.isAuthenticated()){
if(req.isAuthenticated()){
//
}
else{
res.redirect('/users/login');//your particular login routes
}
});
Good question, I had some issues while trying to implement something like this, when there is a un-authenticated request the handlebars skips the if block if the res.locals variable returns a falsy value. To solve this issue you need to setup a middleware in your app.js file to make the req.user available globally in your app Like so..
app.use(function (req, res, next) {
res.locals.login = req.user;
next();
});
In your header file you can do this check for authenticated user and display according content like so..
{{#if login }}
<li>User Account</li>
<li role="separator" class="divider"></li>
<li>Logout</li>
{{/if}}
{{#unless login}}
<li>Sign up</li>
<li>Sign in</li>
{{/unless}}

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