This is my first web development and my first use of a database.
With help of this Q&A I understand the purpose of sessions.
Up to now I have used 'express-session'.
const session = require('express-session');
let sess = {
//store: ,
secret: cryptoString,
resave: true,
saveUninitialized: true,
cookie: {
path: '/',
maxAge: 8 * 60 * 60 * 1000, //h * min * s * ms
},
name: 'data',
}
server.use(session(sess));
server.post('/lgn', (req, resp) => {
let session = req.session;
});
I have uploaded my code to heroku and it works. But I get the warning:
"connect.session() MemoryStore is not designed for a production enviroment, as it will leak memory, and will not scale past a single process."
Another Q&A gave me an impression of the problem. Now I'm confused about the class Session in my back4app database. I guess, I should have used them instead of the server memory. But how? I was looking for a simple, straightforward example and have found nothing.
Could you provide an example please? The Parse Doc is not enough for me. A coded, running example would be very helpful.
Related
I am using the following Node.js code to create a 'session store' to keep user information. These text files are kept in a folder called "session-store":
var session = require('express-session');
var FileStore = require('session-file-store')(session);
app.use(session({
store: new FileStore({path: './session-store'}),
// using FileStore with express-session
// as the store method, replacing the default memory store
secret: 'secret_key',
name: 'myadmin',
resave: false,
saveUninitialized: false,
cookie: { maxAge: 60000, httpOnly: true, secure: false }
}));
app.get('/', function (req, res) {
if (req.session.views) {
req.session.views++;
} else {
req.session.views = 1;
}
});
My text file which contains the session information seems to generate properly. However I have some confusion regarding its proper usage. In my cookie (.txt) file, it reports the "views" correctly, such as ""views":1". However if I define another variable, such as "req.session.broadcast = String(req.body.usr);" I do not see this information in my text file...why would this not be inclusive? Is this because the .txt file containing the cookie session storage information is generated only on the initial 'route' (i.e. the "app.get('/', function (req, res) {...do stuff}") and no other place in the Node.js code? (NOTE: I have "req.session.broadcast" set in a different route other than the 'homepage' route...which I guess is when the cookie file gets generated...possibly?).
I am simply attempting to properly manage users...therefore I want to be able to have certain session variables properly set and tracked for each unique user browser.
Are the "req.session.user" and/or req.session variable(s) 'hard coded' variables? I believe they get set when the browser is directed at the webpage, however how can they be used to terminate a session? Do they automatically become null if the user closes their browser (using the "x" in the right top corner) OR if the user directs their browser to another webpage...?
Any help with these questions and any other advice would be GREATLY appreciated.
** SOLVED **
I've been struggling with this one for a bit. Lots of similar posts out there, but none of the proposed solutions are working for me.
I'm using Express and Passport with cookie sessions. When I pass just the secret to cookieSession everything works fine:
app.use(express.cookieParser('MySecret'));
app.use(express.cookieSession('MySecret'));
app.use(passport.initialize());
app.use(passport.session());
But the default cookie is session-based, and so it clears when you close your browser. I need a time-limited cookie. So I tried using the supposedly supported options:
app.use(express.cookieParser('MySecret'));
app.use(express.cookieSession({
secret: 'MySecret',
cookie: {
maxAge: 365 * 24 * 60 * 60 * 1000
}
}));
app.use(passport.initialize());
app.use(passport.session());
And it stops working. Seemingly the cookie is set in my browser and looks good, but there's no req.user, and subsequent requests are not authenticated.
I tried using maxage instead of maxAge to no avail. I can switch to the same config, but using express.session() instead of express.cookieSession() and it does work, but the session is lost when the server is restarted.
Any help?
edit: I'm on Express 3.20.2 btw
This was user error. I'm not sure where I got the syntax for passing just the secret as a string to cookieSession() but that's invalid. It gets ignored, and actually falls back to using req.secret which is defined by the cookieParser('MySecret') call in the first place.
So that's why it was working with the original code. I still think this is a wtf moment though, because the second syntax should still work, but it doesn't. It boils down to this snippet in the cookieSession module:
if (!options.secret && req.secret) {
req.session = req.signedCookies[key] || {};
req.session.cookie = cookie;
} else {
// TODO: refactor
var rawCookie = req.cookies[key];
if (rawCookie) {
var unsigned = cookieParser.signedCookie(rawCookie, secret);
if (unsigned) {
var original = unsigned;
req.session = cookieParser.JSONCookie(unsigned) || {};
req.session.cookie = cookie;
}
}
}
So when you do pass a secret in the options for cookieSession it falls into the else block, and ends up setting a different cookie? I don't know, but it seems like a bug. If I'm using the same secret for both cookieParser and cookieSession it should be good. But anyway...
========
tl;dr it needs to be this:
app.use(express.cookieParser('MySecret'));
app.use(express.cookieSession({
cookie: {
maxAge: 30 * 24 * 60 * 60 * 1000
}
}));
I may just not understand exactly how Express manages sessions, but when I set the session to expire in 7 days e.g.
app.configure(function () {
app.set(express.static(__dirname + '/public'));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
expires: new Date(Date.now() + (60 * 60 * 24 * 7 * 1000)),
secret: ''
}));
});
The cookie is set to expire when the browsing session ends as opposed to the 7 days specified.
If I change the above code e.g.
app.configure(function () {
app.set(express.static(__dirname + '/public'));
app.use(express.bodyParser());
app.use(express.cookieParser());
app.use(express.session({
cookie: {
expires: new Date(Date.now() + (60 * 60 * 24 * 7 * 1000)),
},
secret: ''
}));
});
The cookie is set to expire in 7 days correctly; does this also expire the session on the server too in 7 days time? I would have thought the two were coupled by default.
For bonus points; in production the sessions will be stored in Redis or similar, but during developing I am storing them in memory. Is there a way I can see this data to verify when it is set to expire too?
For even more points! The sessions are not 'rolling' by default I believe? I have read that req.session.touch() will reset the session; does this reset the session cookie's TTL too? If not, how would you suggest I 'roll' the sessions e.g.
The session is initially set to 7 days.
On day 3 the user returns and the session expiration is reset to 7 days from this visit.
Etc.
So the user could have a perpetual session, so long as they were active once in any rolling 7 days.
As always, help is much appreciated!
MemoryStore is the default, it is very simple, and it do not support for TTL.
source code
If you want to access to MemoryStore, just do it like this:
var ms = new MemoryStore();
app.use(express.session({
store: ms
...
}))'
ms.all(function (err, array_of_session) {
console.log(array_of_session);
});
You should use redis or mongo to store session. For example connect-mongo, it support TTL and replica set.
https://github.com/kcbanner/connect-mongo
Session rolling?
No, you can do it yourself
read this
https://github.com/senchalabs/connect/issues/670
I understand that you can set the maxAge when starting up the app as follows:
connect.session({ secret: 'keyboard cat', cookie: { maxAge: 60000 }})
However, i would like to implement something along the lines of "remember me" setting, how would i go about doing that?
Thanks a lot :)
Jason
You can set either expires or maxAge on the individual cookie belonging to the current user:
// This user should log in again after restarting the browser
req.session.cookie.expires = false;
// This user won't have to log in for a year
req.session.cookie.maxAge = 365 * 24 * 60 * 60 * 1000;
See connect session documentation.
I'm (almost) successfully using Node.js with Express and Redis to handle sessions.
The problem I'm having is that the session is not kept when I use res.redirect().
Here is how I can see it :
req.session.username = username.toString();
console.log(req.session);
res.redirect('/home');
The console.log() prints :
{ lastAccess: 1322579131762,
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 29 Nov 2011 15:06:31 GMT,
originalMaxAge: 60000 },
username: 'admin' }
Now, here is the following code :
app.get('/home', [app.requireLogin], function(req, res, next) {
// Not showing the rest as it's not even getting there
// Instead, here is what's interesting
app.requireLogin = function(req, res, next) {
console.log(req.session);
This console.log() prints out this :
{ lastAccess: 1322579131775,
cookie:
{ path: '/',
httpOnly: true,
_expires: Tue, 29 Nov 2011 15:06:31 GMT,
originalMaxAge: 60000 } }
Clearly, the 'username' object has disappeared. The session has not kept it, and just rebuilt a new one.
How can I solve this? Don't hesitate if you need any information.
Here is the code where I set the session management :
app.configure(function() {
// Defines the view folder and engine used.
this.set('views', path.join(__dirname, 'views'));
this.set('view engine', 'ejs');
// Allow parsing form data
this.use(express.bodyParser());
// Allow parsing cookies from request headers
this.use(express.cookieParser());
// Session management
this.use(express.session({
// Private crypting key
secret: 'keyboard cat',
store: new RedisStore,
cookie: {
maxAge: 60000
}
}));
this.use(app.router);
});
Here is the whole project (I mean, parts of it), on gist : https://gist.github.com/c8ed0f2cc858942c4c3b (ignore the properties of the rendered views)
Alright, I found the solution. The problem is that the time in maxAge was added to the current date. So, in the browser side, the cookie was set to expire at the GMT time shown.
The problem was the following : I use a virtual machine to test node.js, and, you know... sometimes, you suspend your machine.
Well, what happened is that the machine's time was two days late. So, whenever the cookie was set on the server side, the client side thought the cookie was already expired, since my host machine was not two days late.
Another stupid outcome.
Did you try with different browsers ? Are you keeping the same session id between page redirects ?
You could add req.session.cookie.expires = false; before redirecting...
Your code looks pretty solid, but is there a reason you're using client.end()? It forcibly closes the redis connection and is not clean. I don't think you need it at all:
https://github.com/mranney/node_redis/issues/74
I am not sure about the underlying architecture for connect-redis, but I'm wondering if calling client.end is what's resetting your sessions. What happens if you take those out?
I was having a similar problem in that I was setting something on the session that was not persisting outside the app.get() it was set in.
My problem turned out to be that I was not doing a res.redirect() at the end of my app.get(). Looks like I was setting something on a request object and then allowing it to get garbage collected.
I added a res.redirect( '/nextmethod' ) and the data persists just fine.
Surely you need to save that session in some way, this might work.
req.session.regenerate(function(){
req.session.username = username.toString();
res.redirect('/home');
});