Cannot get session data from middleware in node.js - node.js

I have a function that gets the id of the user when she registers
user.save(function(err, id){
if(err) return next(err);
req.session.uid=id;
})
Then, I wrote this middleware
var User = require('../user');//contains the code above
module.exports = function(req,res,next){
var uid = req.session.uid;
if(!uid) return next();//if not logged in
else{//else is logged in
User.get(uid, function(err, user){
//get user object and pass it to locals
if (err) console.log("error from midd > "+err);
req.user = res.locals.user = user;
next();
})
}
}
I define my middleware in the app.js like so
var user = require('./lib/middleware/user');
app.use(session({resave:'false', saveUninitialized:'false', secret:'secret'}));
app.use(user); //<-- my middleware
app.use(express.static(path.join(__dirname, 'public')));
app.set('multimedia', __dirname + '/public/multimedia');
app.use(messages);
app.get('/register', register.form);
app.post('/register', register.submitit);
Then I check if there is an id in the locals and show the right menu, by using ejs
<%if (locals.user) {%>
<div id='menu'>
<a href='/post'>post</a>
<a href='/logout'>logout</a>
</div>
<%}else{ %>
<div id='menu'>
<a href='/login'>login</a>
<a href='/register'>sign up</a>
</div>
<%}%>
This never works. In every page, even if I am registered, I never see the menu for the registered users (post and logout).
I put many console.log all over the code and looks like the middleware never gets the session.uid.
console.log("req.session.uid = "+req.session.uid); inside the middleware always gives undefined, even though saving the user works and returns an id that I pass to session req.session.uid=id;
How do I fix this? Please advise because I am stuck.
Thanks

Note: I cannot be sure this is your error because you didn't paste the code around user.save(). But I'm enoughly confident that is the cause.
Session.Save(): This method is automatically called at the end of the HTTP response if the session data has been altered (though this behavior can be altered with various options in the middleware constructor). Because of this, typically this method does not need to be called.
As I can see here:
user.save(function(err, id){
if(err) return next(err);
req.session.uid=id;
})
You either:
Fail to save the new user and continue the process with next(err) (which end the HTTP response)
Or succeed and probably get stuck (<= not enough code shown to know what...)
In case of success you should probably call next() or next(null).
Because of that, the altered session (ie: req.session.uid=id;) is never saved. Thus, resulting in a failure of retrieving the uid in the middleware.

Related

how to pass data and redirect in express

My code is
main.post('/userlist', function(req, res, next) {
// where did you get this?
// var db = req.db;
var query = connection.query("SELECT name,zaman,giriscikis FROM giriscikis where date_format(zaman,'%Y-%m-%d') between ? and ?", [req.body.bas, req.body.bitis], function(err, result) {
if (err) throw err;
console.log(result);
res.send(httpResponse(result));
return res.redirect('/zamansorgu');
//console.log(req.body.bas)
//console.log(req.body.bitis)
});
});
I want to fecth data from database and redirect to same page in the code(zamansorgu.html)
But I get an error
Cannot set headers after they are sent to the client
How can I solve this problem
thank you for your helps
You are attempting to send back JSON data and redirect to a different page. That's not possible. Each endpoint request can have one response, not more. You can either send back the data, or redirect. That's because redirecting really does send back data too (the html of the new target page).
Think about it from the caller's point of view. If it did allow this how would it work? If someone uses this link from a browser should the browser show the JSON data you returned, or should it take the user to the new page?
The error is saying "hey, I already sent back data. I can't redirect now because we are already down the path of returning some JSON".
If you want to use the data to format the output that can be done, or if you want to redirect to a new location and pass the data in the url, that's also possible. Consider code like this:
main.post('/userlist', function(req, res, next) {
// var db = req.db;
var query = connection.query("SELECT name,zaman,giriscikis FROM giriscikis where date_format(zaman,'%Y-%m-%d') between ? and ?", [req.body.bas, req.body.bitis], function(err, result) {
if (err) return next(err);
if (result.urlparam) {
// this builds a new url using the query value
const nextUrl = `/zamansorgu?param=${result.urlparam}`;
return res.redirect(nextUrl);
}
else {
// this builds html here
const html = `<html><body><h1>${result.title}</h1></body></html>`;
return res.send(html);
}
});
});
I also ran into this, in my case it was quite a deceptive little bug. A node-inspector session helped me pinpoint the problem quickly however. The problem in my case was pretty bone-headed, the res.end call in the sample below is the offending line.
res.writeHead(200, {"Content-Type": "application/json"});
res.end(JSON.stringify(someObject));
someObject did not exist after a refactor and that was causing a ReferenceError to get thrown. There is a try-catch in Router.prototype._dispatch that is catching the ReferenceError and passing it into next
res.status(301).redirect(`/zamansorgu?name=${"John"}&email=${"john#email.com"}`)
So, this is something I explored but it will be dependent on the structure of your application. You could always pull the data out using query params and hydrate your application.

Express-validator does not catches errors

In node 8.11.1, express 4.16.3 I installed
"express-messages" : "*",
"connect-flash" : "*",
"express-validator" : "*",
"express-session" : "*"
I have a page that gets all articles app.get('/', function(req, res){.... and also has a "New" button, for adding a new article. When hitting New, a pop-up Bootstrap form appears.
I want to check for empty form fields. The HTML form field that I check is
<input type="text" name="name" id="name" class="form-control" />
The form's action goes to
const { check, validationResult } = require('express-validator/check');
app.post('/add', [check('name').exists()],
function(req, res) {
const errors = validationResult(req);
console.log(errors.isEmpty());
if (!errors.isEmpty()) {
req.flash('err', 'errors'); //test
res.redirect('/');
}
else {
pool.connect(function(err, client, done) {
if (err) {
return console.log('db connect error '+ err);
}
client.query('insert into event (name) values($1)',
[req.body.name]);
done();
req.flash('success', 'saved');
res.redirect('/');
}); //pool connect
}//else
});
I am based in this. Whatever I do, the console.log(errors.isEmpty()); is always TRUE, so I end up saving to my DB empty fields. So, the express-validator does not catches errors ?
Also, I am not sure how to pass the errors back in the / route, so the errors can be rendered, this is why I just use req.flash('err', 'errors'); for now. Do I use req.flash like for the success part?
Please help me debug this.Thanks
express-validator maintainer here.
Regarding express-validator letting empty strings come through
check() will create a validator chain for something in the request named name.
It's not assertive of the location of the field, it could be req.query.name or req.body.name, for example.
If you want specifically req.body, then use the other chain creator body().
Then, even if you do have name in req.body, please note that check('name').exists() is not validating its content. It's simply checking it exists, as the name says.
If you want to check that it has some content, whatever that is, you can use check('name').not().isEmpty().
Regarding passing the errors to the redirected page
You can call either errors.array() or errors.mapped() to get the actual errors (please check the Validation Chain API for details).
I haven't used req.flash, so you should test if you can pass an JS object in there, or if you can only pass strings.
If you must use a string, then JSON.stringify/JSON.parse should be your friends to transport your errors.

How to add current logged in status to Users Schema in MongoDB using Passport and node.js

I’m quite new to backend development…
With using my API I would like to be able to display a list of users and also indicate if they are currently logged in. I got the basic authentification working using passport and json web token
I’m not looking to get the current logged in user.
I want to be able to retrieve a list of users and see if they are logged in or not.
Like this:
var users = Users.find({});
// console.log(users) output:
{
name: 'foo'
password: ...
isLoggedIn: false
},
{
name: 'bar'
password: ...
isLoggedIn: true
},
{
name: 'baz'
password: ...
isLoggedIn: false
}
isLoggedIn would be set to true if the user is currently logged in and to falseif not.
How can I do that? Thank you!
It sounds like what you would like to do is update your MongoDB database based on login/logout events. To do this you could use something like mongoose to work with your Node backend to easily access your database in MongoDB.
You can include mongoose after installing with npm install mongoose like so:
var mongoose = require('mongoose');
var User = mongoose.model('User');
Note that User corresponds to whatever schema you create for storing user information.
Assuming you have some sort of router object for handling requests, you could construct route handlers for /logout and /login and use your imported mongoose User model to retrieve and then modify a specific User object as such:
// whenever user goes to '/login' (you can have, say, your 'login' button make a request to this URL
router.get('/login', function(req,res) {
// your authentication here; passport stores the currently authenticated user in req.user
var username = req.user.name; // here we assume the username is stored as 'name' as you have in your code but change this based on your schema
User.findOne({name: username}, function(err, user, data) {
if(err) res.send(err);
user.isLoggedIn = true;
user.save(function (err) {
if (err) {
console.log(err);
} else {
// redirect to some page here maybe
}
});
});
});
// whenever user goes to '/logout' (you can have a logout button make a request to this URL
router.get('/logout', function(req,res) {
// currently authenticated user is still in req.user
var username = req.user.name;
User.findOne({name: username}, function(err, user, data) {
if(err) res.send(err);
user.isLoggedIn = false;
user.save(function (err) {
if (err) {
console.log(err);
} else {
// redirect to login/register page maybe
}
});
});
});
So to summarize what this code would do:
based on the url a user would go to, our route handler would fetch one correct, unique User object from our database based on the name (username)
it would do so by accessing the username property of req.user which corresponds to the currently authenticated user with Passport, which, again will be different for all users
update the field that we use to keep track of login status (isLoggedIn)
and then save the changes, after which we are done updating the state to reflect whether the user is logged in or not, so we can now redirect to some other page or display other content
Finally then, you could retrieve a list of all users similarly to your code like so:
User.find({}, function(err, users, data) {
// all users from your database are in `users`
console.log(users);
});
Edit for expired sessions:
So, to track expired sessions, since you're using Passport, would in theory require functionality to signal with some sort of event / callback / message, etc. the moment the session is deemed invalid. Now that is tough to monitor and from my experience with Passport, stuff like that isn't implemented in all authentication strategies and might vary based on the strategy to be used by developers (think for instance if a browser window is closed, based on Passports authentication strategy, or just browser, it might destroy the cookie for the session right away and our server has no way of knowing about it). I do recommend checking out all the authentication strategies Passport offers in case there are some better ones here.
Now, if you would like to add functionality to track the users passive login/logout status with sessions yourself, you could use something related to cookies. Again, not necessarily one to use, but here's a couple handy Express modules: cookie-parser and cookie-session.
Then, you could set and read cookies like this, using cookie-parser:
var express = require('express');
var cookieParser = require('cookie-parser');
var app = express();
app.use(cookieParser());
You would put this code somewhere right after the user is authenticated:
// cookies are stored here
console.log(req.cookies);
// configure your cookie
var options = {
expires: 1000 * 60 * 60, // expires after one hour
httpOnly: true
}
// Set cookie
res.cookie('session', ('user-' + req.user.name), options);
And then, on the client side check if that cookie is valid continuously on some time interval, and if it expired Date.now() > cookie.expires then make a GET request to /logout, and there log out the user (currently still authenticated) by updating MongoDB and all.
However, since this would require making a mechanism to basically simulate an expired session, I would recommend using something analogous to a timeout, which would be much easier to implement. Just a note, this is sort of analogous to mechanisms on some pages you might have encountered where you get a pop-up saying 'You will be logged out due to inactivity'. In your main.js or whatever client-side script define a function to keep going on a time-out, unless the user does some action.
var inactivity = function () {
var t;
// user doing something on your page, so keep resetting time counter when events happen
document.onmousemove = resetTimer;
document.onkeypress = resetTimer;
// this is a callback function that will get called once a time-out countdown is done
function timeOut() {
// make a request to '/logout' here and logout the current user (you still will have access to req.user from Passport)
// also can redirect from back-end route handler to the login page for instance
}
// this gets called whenever an event happens, resetting the counter of sorts
function resetTimer() {
t = 0;
t = setTimeout(timeOut, 1000 * 60 ) // set this to however long you should wait to log out your user time (in milliseconds)
}
};
So basically what this approach would let you do, is automatically invalidate sessions yourself, which means you would have much greater control over updating the state of your database and logging users out.
Hope this helps!

nodejs express profile property in request

I got very confused for one usage:
In the route file:
app.param('userId', users.load);
And the users.load function:
exports.load = function (req, res, next, id) {
var options = {
criteria: { _id : id }
};
User.load(options, function (err, user) {
if (err) return next(err);
if (!user) return next(new Error('Failed to load User ' + id));
req.profile = user;
next();
});
};
Here, route should have the userId to response but why does the author use req.profile here. profile is not a property.
Anyone can help?
Thanks.
What the code does is this: for routes that have a userId parameter (that is, routes that look similar to this: /user/:userId), Express will call the load() function before the route handler is called.
The load function loads the user profile belonging to the userId from the database, and adds it to req as a newly created property req.profile.
The .profile property name is arbitrarily named by the author and demonstrates the fact that it's perfectly valid to add properties to req (or res, for that matter, but convention is to add these properties to req).
In the route handler, you can then use req.profile. It's basically a way of propagating data from middleware and app.param() implementations to other parts of the route handling.
the line req.profile = users; think of it this way, 'i want to take all the powers of the users and paste them to req.profile' why? remember this part is sort of a middleware if you want to target any of the read, update and delete code it has to pass through here, it only makes sense if it involves the req, because you are practically requesting to access the said pages (read, edit and delete or any other:userId page) now the profile name doesn't matter you could use any name but its sort of a convention in the community to use the profile name.

Node/Express/Jade passing username back to view

This is my first project with all these technologies, I typically do Angular, but I am working for a charity ( and keen to learn node ). This is day three.
During a login, this is the method called:
schema.statics.authenticateAndLoad = function(req, res, next) {
var userId = req.body.email;
res.locals.userId = userId;
This is supposed to store the value so it doesn't need to be reentered. If login fails, it does this:
return next('Login failed. Please enter your details and try again.');
Then in my Jade template:
if(locals.userId)
p Welcome to #{userId}
else
p Welcome
The actual template has code to try to do what I want:
input(type='text', name='email', id="inputEmail", placeholder="Email", value="#{body.email || ''}")
But this does not work.
So, I THINK this means my setting a value in the result is lost when I call 'next', but, because it's also passing in this error object to show on the screen, I'm not sure how I would go about making sure this error shows AND make the value pass through . Right now, my text just says 'welcome' and never 'welcome to xx', this is test code, I'm just proving the value is not being passed through.
My question is, what's the correct way to pass the value through to my template, and ALSO trigger the error message that is being shown.
The code, when I step in to it, goes deep in to Express and checks for errors there.
Hi it is good to see some developers doing charity work.
Typically what you would use is something like this assuming this is a piece of middleware
schema.statics.authenticateAndLoad = function(req, res, next) {
var userId = req.body.email;
res.locals.userId = userId;
loginFunction(userdetails,function(error,result){
//if there is an error you need to render the page or do a redirect to the
//login page
if(error){
var msg = 'Login failed. Please enter your details and try again.'
return res.render('login',{userId: userId,error: msg})
//this renders the login page and passes req.body.email to the page as userID and the msg as error
}
if(result){
//if this is correct you return next() as you are saying
//you may go through
return next()
}
}
}
then on your jade to display the error you use and userID
p #{userID}
p #{error}
So to answer your question the correct way to send the value to jade you pass it in using this and pass the error in as a variable.
return res.render(template_name,{userId: req.body.email,error: msg})
I hope this helps you out

Resources