I am trying to use connect/express cookieSession() in order to store my node.js sessions in cookies (and thus, avoiding a server-side session store). This would help me to 'remember' the user when they log in and keep sessions alive even after server restarts.
I would like to do this with cookieSession():
app.use( express.cookieSession( { secret: 'secret_key' } ) );
app.use( function (req, res, next) {
if ( req.method == 'POST' && req.url == '/login' ) {
if ( req.body.remember ) {
req.session.cookie.maxAge = 30*24*60*60*1000; // Rememeber 'me' for 30 days
} else {
req.session.cookie.expires = false;
}
}
next();
});
However, this does not work, because req.session.cookie is undefined. I also tried the following, but it didn't seem to work:
app.use( express.session( { secret: 'secret_key' } ) );
app.use( function (req, res, next) {
if ( req.method == 'POST' && req.url == '/login' ) {
if ( req.body.remember ) {
req.cookies['connect.sess'].maxAge = 30*24*60*60*1000; // Rememeber 'me' for 30 days
} else {
rreq.cookies['connect.sess'].expires = false;
}
}
next();
});
Starting out with
app.use(express.cookieSession({ secret: config.server.cookieSecret }));
And changing it to
app.use(function(req, res, next) {
express.cookieSession({
secret: config.server.cookieSecret,
cookie: {
maxAge: req.param('remember') ? 20000 : 3000
},
})(req, res, next);
})
So, we create our own middleware, wrapped around the cookieSession middleware, changing the maxAge based on a param.
So, whenever you change the session you'll need to pass a remember in the body, query, or params( that's where req.param() looks ). In most cases, you only set a user_id to the session once, at login.
It's 3 seconds or 20 seconds to test and ensure it works.
And again, it might be not very helpful if you're setting stuff to your session a lot, but if you just set a user_id to session at login, this is all you need.
If you are setting lots of stuff to your session, you should know that data get passed around at every request, and you should save only the minimum to the session, like user_id, then look up the data you need for each request, to keep the overhead down on the user.
I think this does what you want:
// Using express.session instead of express.cookieSession
app.use(express.session({ secret : 'secret_key' }));
app.use( function (req, res, next) {
if ( req.method === 'POST' && req.url === '/login' ) {
if ( req.body.remember )
{
req.session.cookie.maxAge = 30*24*60*60*1000;
// needed to make the session `dirty` so the session middleware re-sets the cookie
req.session.random = Math.random();
}
else
{
req.session.cookie.expires = false;
}
}
next();
});
cookieSession does some funky stuff, like del req.session.cookie (not sure why).
You have to first set req.session.cookie so that you can set maxAge. Trying to use it before you set it gives req.session.cookie is undefined
express.cookieSession has default values which it accepts, see here. You should mention all the parameters you are going to use. You can set cookie via the following :
app.use(express.cookieSession({ secret: 'secret_key', cookie :{ path: '/', httpOnly: true, maxAge: 30*24*60*60*1000} });
A little late to the table but I thought this answer may help people going forward...
I was using cookie-session which doesn't create a cookie object on request.session. To properly implement rememberMe functionality using request.session.cookie I switched cookie-session to express-session and that solved everything. So now there is a cookie object on session and doing this inside of a request is possible...
npm install express-session
app.post('/login', function(request, response, next) {
passport.authenticate('local', function(err, user, info) {
if(err) return next(err);
if(!user) {
request.flash('loginMessage', info.message);
return response.redirect('/account/login');
}
request.login(user, function(err) {
if(err) return next(err);
if(request.body.rememberMe)
request.session.cookie.maxAge = 2592000000;
else
request.session.cookie.expires = false;
return response.redirect(options.redirect);
});
})(request, response, next);
});
This is also pretty late but it might help other people.
It seems like to me the best way to persist your session data is to store it in something like redis. The question asked for a way that didn't use server storage, but I think he was referring more to MemoryStore. Maybe not but either way this is what I did.
I used express-session and connect-redis
npm install -g connect-redis
npm install -g express-session
Then you configure stuff.
// session modules
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session')
var redisStore = require('connect-redis')(session); // this sets up Redis to work with your session cookies
var app = express();
Then you just initiate your session with the store option set to your redisStore.
The maxAge part sets the lifetime of each session to an hour, the session middleware resets it when it's accessed.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(session({
store: new RedisStore({
host:'127.0.0.1',
port:6380,
prefix:'sess'
}),
cookie: {maxAge: 3600000 },
secret: 'session_secret'
}));
Now when a client connects, express should store the session data automatically in a Redis data structure. Since it's not just cached in memory, your server can crash and still have all the relevant session data still available at the IP address and and port specified.
Yummy seems to allow modifying cookies expiry after creation.
Related
I just need to manage the concurrence on my app built with nodejs on the top of the nestjs framework.
As a far as I know, the most simplest way to do that is controlling that online one session user in expressjs is alive.
I am not taking care about security or whatever other issues, just want to know how many users are connected and restricting it to only one user session till its session is expired.
Here is my codebase
var express = require('express');
var session = require('express-session');
var app = express();
var numConnections = 0;
app.use(session({
cookieName: 'sessionTest',
secret: 'eg[isfd-8yF9-7w2315df{}+Ijsli;;to8',
cookie: {
secure: false,
maxAge: 1000 * 10,
sameSite: true
}
}));
app.use((req, res, next) => {
console.log(req.session.store)
console.log(req.session.ip)
console.log(req.session.useragent)
console.log(req.connection.remoteAddress)
console.log(req.headers['user-agent'])
if (numConnections === 0
// && req.session
) {
req.session.ip = req.connection.remoteAddress;
req.session.useragent = req.headers['user-agent'];
req.session.page_views = 1;
res.send("Welcome to this page for the first time!");
numConnections++;
console.log(req.session);
next();
}
else if (numConnections == 1 &&
req.session.ip === req.connection.remoteAddress
&& req.session.useragent === req.headers['user-agent']
) {
req.session.page_views++;
res.send("You visited this page " + req.session.page_views + " times");
console.log('TEST');
next();
} else {
console.log('There is someone using the app!!!');
return res.sendStatus(401);
}
})
app.listen(3001);
I really appreciate if someone can help me
You could use the store to retrieve the current amount of open sessions. The doc says stores may implement length and/or all methods. However, it appears that only the default MemoryStore handles these. You can look at all the compatible store implementations at the bottom of the page and pick the one that fits your environment.
It probably (i.e. not tested) looks like this:
var session = require('express-session');
var memoryStoreThatWillBeChangedBeforeLiveEnvironment = new MemoryStore();
...
app.use(session({
...
store: memoryStoreThatWillBeChangedBeforeLiveEnvironment
}));
app.use((req, res, next) => {
memoryStoreThatWillBeChangedBeforeLiveEnvironment.length((err, size) => {
if (err) return res.status(418).send("I'm a teapot");
var numConnections = size;
// call your code here
})
});
(Quite obviously, if an implementation only offers the all method, you can count the returned array of sessions.)
I'm using express-session for handling session variables in a NodeJS Application. I use session variables for handling login-authorization, for saving logged user information and other things.
The thing is that this session variables are being shared for all clients, it looks like they are working as NodeJS instance variables instead of session variables for every client. What I want to have is session variables working as they work in PHP.
This application is retrieving all the data from web services in a Laravel Back-End application.
This is my code:
Initializing session:
var sessionHelper = require('./helpers/session-helper');
var session = require('express-session');
app.use(session({
secret: config.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: {secure: true}
}));
sessionHelper.init(session);
global.SESSION = sessionHelper;
session-helper module:
var _session = null;
module.exports = {
init: function (session) {
_session = session;
},
has: function (name) {
return ((_session[name]) ? true : false);
},
get: function (name) {
return _session[name];
},
set: function (name, value) {
_session[name] = value;
},
clear: function (name) {
_session[name] = undefined;
}
};
Using session variables:
SESSION.set('hotels', response.hotels);
SESSION.get('hotels');
Thanks,
The problem is that you've globally cached a specific instance of session in your helper object. As a general practice, that's not a good idea unless you are very sure about how that object's lifecycle and state are managed.
The way that express sessions work is that the express middleware maintains a separate instance of session per request. You should be accessing that session typically in the body of a request:
app.get('/', function(req, res, next) {
var sess = req.session;
// sess will have values specific to each unique browser session
console.log('This session has an id of ', sess.id);
});
If you still feel you want to setup a helper, you can make that available for every request by configuring Express with the use method before your app.get or any other router methods - here is a rough idea how:
// This should be AFTER the app.use statement for express sessions
app.use(function (req, res, next) {
var sessionHelper = require('./helpers/session-helper');
sessionHelper.init(req.session);
req.sessionHelper = sessionHelper;
next();
})
Now, in any subsequent route handler code, you will find that req.sessionHelper is available for use. This is because you've told Express to first add your helper to the request object for ALL requests. So, this will work:
app.get('/', function(req, res, next) {
console.log('Session ID: ', req.sessionHelper.get('id'));
});
Just remember that you are still responsible for session storage. You need to combine express-sessions with a store (like connect-redis or connect-mongo) in order to persist session-data between restarts. The full list is here: https://github.com/expressjs/session#compatible-session-stores
I try to check if session in Express 4 is exist:
if(req.session.user == undefined) {}
It gives me error:
Cannot read property 'user' of undefined
How I can check if exist value in session?
From the source:
How to use Express Session ?
Before heading to actual code, i want to put few words about
express-session module. to use this module, you must have to include
express in your project. Like for all packages, we have to first
include it.
server.js
var express = require('express');
var session = require('express-session');
var app = express();
After this, we have to initialize the session and we can do this by
using following.
app.use(session({secret: 'ssshhhhh'}));
Here ‘secret‘ is used for cookie handling etc but we have to put some
secret for managing Session in Express.
Now using ‘request‘ variable you can assign session to any variable.
Just like we do in PHP using $_SESSION variable. for e.g
var sess;
app.get('/',function(req,res){
sess=req.session;
/*
* Here we have assign the 'session' to 'sess'.
* Now we can create any number of session variable we want.
* in PHP we do as $_SESSION['var name'].
* Here we do like this.
*/
sess.email; // equivalent to $_SESSION['email'] in PHP.
sess.username; // equivalent to $_SESSION['username'] in PHP.
});
After creating Session variables like sess.email , we can check
whether this variable is set or not in other routers and can track the
Session easily.
Firstly it depends on the library you are using, maybe some libraries have utilities for that, I assume you're using express-session.
This is just Okay:
if(req.session.user){}
They are useless:
if(typeof req.session.user !== "undefined"){}
if(typeof req.session.user !== "undefined" || req.session.user === true){}
The reason: req.session is an object, just like normal objects:
var obj = { name : "adam" }
If you try to get obj.age which it doesn't exist and defined,
the getter function of the object, firstly check if it exists or not, if it's not, it wouldn't produce a fatal error and instead it assigns that property to undefined value.
That's cool, so obj.age get's undefined ( JS has undefined as a value type), moreover undefined is a falsy value (when you coerce it to boolean it becomes false, so it's falsy), which means you can simply check it in conditional statements like this: if(obj.age){}
You can't just create a session without any middleware (Im assuming this is what you've tried).
Read up on the express-session middleware docs, found here:
https://github.com/expressjs/session
Basic implementation example:
Create a session:
app.use(session({
genid: function(req) {
return genuuid() // use UUIDs for session IDs
},
secret: 'keyboard cat'
}))
To read a session:
// Use the session middleware
app.use(session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }}))
// Access the session as req.session
app.get('/', function(req, res, next) {
var sess = req.session
if (sess.views) {
sess.views++
res.setHeader('Content-Type', 'text/html')
res.write('<p>views: ' + sess.views + '</p>')
res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>')
res.end()
} else {
sess.views = 1
res.end('welcome to the session demo. refresh!')
}
})
There are a number of tutorials you can find online, e.g:
https://www.thepolyglotdeveloper.com/2015/01/session-management-expressjs-web-application/
The issue you are facing is maybe you are not using the session middleware in ALL of your requests.
You can check it the following way :
Add this to all of your routes :
app.use(session({ secret: 'keyboard cat',resave:false,saveUninitialized:false, cookie: { maxAge: 60000 }}));
Authentication Route :
router.post('/', function(req, res, next) {
//login logic here
//if login successfull
req.session.user = username //your unique identifier
req.send("Hurray! logged in");
//else
req.send("Credentials error");
});
Check in any route:
router.get('/dashboard', function(req, res, next) {
if (req.session.user)
//do stuff here
else
//redirect to login page
})
This works :)
I am using a basic node express-session setup with memory store and I have this code on the server:
app.use(require('express-session')({
secret: 'keyboard cat',
resave: false,
saveUninitialized: true,
cookie: { secure: true }
}));
app.post('/api/logIn', function(req, res) {
req.session.userName = req.body.userName;
}
app.get('/api/getProfile', function(req, res) {
User.findOne({'userName' : req.session.userName},
function (err, userProfile) {
console.log('getProfile executed for user:' + req.session.userName);
if (err) throw err;
console.log(userProfile);
});
});
The problem is that req.session.userName from getProfile route is undefined, although it is not in the previous request to logIn route. I inspected HTTP headers and strangely there are no headers dealing with cookies, from the server or from the client. Right now I have no idea what could be the problem.
You say cookie: { secure: true }, but is your web server actually on a secure connection? If not, then the cookie won't be written.
From the docs:
Please note that secure: true is a recommended option. However, it
requires an https-enabled website, i.e., HTTPS is necessary for secure
cookies. If secure is set, and you access your site over HTTP, the
cookie will not be set.
Also its important to note if you are using fetch() to make your API calls to include { credentials: 'include' } in the options of your fetch() call. Otherwise the cookie will not set properly and your session will not persist. Make sure that on your server side you do something like:
app.use((req, res, next) => {
res.setHeader('Access-Control-Allow-Credentials', true);
next();
});
so that your headers are set properly and cors wont be an issue. Took me awhile to figure this out but its working now!
The session need is stored in a cookie, so we use this to parse it, some like this:
var cookieParser = require('cookie-parser');
// must use cookieParser before expressSession
app.use(cookieParser());
Full example: http://code.runnable.com/U0tEnHwraXYyp-JG/simple-usage-of-express-session-and-cookie-parser-with-express-for-node-js
Is there a way to control when a session starts with connect's session middleware?
For example, if I have express app config:
var app = express();
app.configure(function(){
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('secret'));
app.use(express.session({ store:sessionStore, ... }));
});
Then on every request, if no session cookie is given, a session is started. What if I wanted to start a session only when the user has been authenticated?
For example, say I have two routes /protected and /login.
If someone hits /protected without a session cookie, the middleware will NOT start a new session. (req.session is null)
If someone hits /protected with a session cookie, the middleware will CHECK to see if there is a matching active session for the cookie and set req.session, but will not start a new session. (req.session could have a value or be null)
If someone hits /login with the correct params, then a session is started explicitly and a cookie is set only then.
The only way to start a session should be explicitly:
app.post('/login', function(req, res, next) {
// connect to database and validate user...
db.authenticate( req.body.user, req.body.pass, function(allow) {
if (allow) {
// START SESSION HERE
// this will send set the cookie
}
});
}
Is there any way of accomplishing this with the existing connect session middleware?
What you want to do is to remove this line:
app.use(express.session({ store:sessionStore, ... }))
Now sessions are disabled by default and it's up to you to decide which controller is going to use them:
var useSessions = express.session({ store:sessionStore, ... });
var preCb = function (req, res, next) {
// authenticate and stuff
// ....
if (authenticated === true) {
next();
}
};
app.post('/login', useSessions, function(req, res, next) { ... });
app.post('/protected', preCb, useSessions, function(req, res, next) { ... });
Even if a session is started every time, it does not really matter because it will be empty. If you are attempting to use it to authenticate access (which seems to be the case), the simplest solution is to set an attribute in your session (such as req.session.authenticated = true;), and check that. This way technically ever visitor has a session, however you will only utilize the session if req.session.authenticated == true. It may not be exactly what you're looking for, but it is the easiest way to get this done.