Now.js quotes:
Simply pass a connect or express http server in nowjs.initialize and this.user.session should be available.
So:
express = require 'express'
app = module.exports = express.createServer()
connect = require 'connect'
nowjs = require 'now'
everyone = nowjs.initialize(app)
The output of this.user is:
{
clientId: '353725111301231610',
cookie: { 'connect.sid': 's0meC00k1e1nF0rm4ti0n' },
session: undefined
}
Any idea why session is undefined?
I ran into this problem and turns out it was happening because I was initializing NowJS before configuring express.
app.configure(function(){
...
app.use(express.cookieParser());
app.use(express.session({ secret: "my_key", store: redisStore }));
app.use(app.router);
});
var everyone = nowjs.initialize(app); //must be defined after app.configure
One thing to note is that session is not set until a request is made to the server so if the server is reset, the client socket will reconnect but session will be undefined until the browser does a page refresh.
I managed to find a solution (CoffeeScript), for every "everyone"-request:
self = this
sid = decodeURIComponent(this.user.cookie['connect.sid'])
sessionStore.get sid, (err, session) ->
self.user.session = session
<<more code here>>
Any way to get to this.user.session directly?
Related
const express = require("express");
const app = express();
var i = new Number;
i=0;
app.get("/", function(req, res){
i++
console.log(i);
});
app.listen(8080);
I created a very small node js project. I have a problem. when I create a variable like above, it doesn't evaluate for each user separately. that is, when a user requests a get, I want it to be 1 each time.
Sample
my problem is that when a jack user enters a site, if he doesn't log out, someone who enters the site's home page from another device enters his account with jack.
how can I do that?
The simplest answer for your question is to simply declare and increment the variable inside the function passed to app.get, but I'm going to assume that you would like a situation where, for a given user's series of requests, the number will increment.
The simplest way to do this is using a server side session, which is provided by the express-session library. Additionally, in order for this to work, you need to call res.end() in order to send the cookie associated with the server session back to the user's browser. More information on sessions generally can be found here.
Below is code to replicate the intent of what you have there, but incrementing for each request from a unique browser instance (identified by the same cookie value associated with the server session):
const express = require('express');
const session = require('express-session');
const app = express();
app.use(session({
resave: false,
saveUninitialized: true,
secret: 'secret',
cookie: {
maxAge: 60000
}
}));
app.get('/', function(req, res){
if (!req.session.value) {
req.session.value = 0;
}
req.session.value++;
console.log(req.session.value);
res.end();
});
app.listen(8080);
My code is listed below but I wanted to explain my thought process and have someone correct me at every point because I have been struggling to try and get this done the RIGHT way.
I've been struggling with this for some time(5days+) and I have not found a straight forward way to do this across the web.
So I have 2 separate node apps running. One running just express-js and another running a websocket server. I'm probably just a complete knucklehead with this, but here goes.
I setup a mongo session store. When a user successfully authenticates, the session gets created and I can re-direct the user to the logged in page. While the session lives, when the user hits the 'auth-page' I can just auto redirect the user to the 'logged in page'.
Now my understanding is, when the session gets created in the mongo-store, a cookie gets created on the web browser and it is this cookie that gets to the server for each request the page makes and express-js will nicely handle the magic internally for me and I can use something like
app.post('/', function (req, res) {
}
Where the req variable gets populated with the session id by express, because express got the cookie and decoded it.
This next part is where things are dicey and any suggestions in anyway will be a huge help.
What i'm wanting to do is, inside my app.post('/'...etc) is redirect to another page. This page loads a client which initiates a websocket connection to my websocket server and my websocket server is able to use this same session-id.
So here's the thing. My express-js http server runs as a separate process with its own port and my websocket server runs as a separate process with its own port as well. After doing enough research online, I found out many sources which indicated that, when my browser makes the connection to my websocket server it will send the cookie in the header somewhere to my websocket server. So in the browser, I have some javascript code that runs:
let clientSocket = new WebSocket("ws://socket.server.address:5005");
So then from my node websocket server, I can parse out the socket.upgradeReq.headers , get the cookie, and use that to get the session id and i'm in business. That describes what I've attempted to achieve below in my code. I have been successful doing this, however I've hit different issues when trying to parse the cookie.
Sometimes I get a single cookie & sometimes, I get multiple cookies taking the form
cookie_name1=cookie_value1;cookie_name2=cookie_value2;
cookie_name3=cookie_value3;cookie_name4=cookie_value4;
cookie_name5=cookie_value5;
Sometimes I get a single cookie & sometimes, I get multiple cookies taking the form
question 1 - why do I get multiple cookies being sent to my websocket server? Is that dictated strictly by the browser? What can I do about that if anything?
question 2 - Will the cookies ALWAYs come in that format? I would hate for the semicolon delimiter style to change and that break my code
question 3 - upon reviewing my code, my thought process can you suggest and guide me with a complete different/better implementation to achieve this? Can you suggest I change parts? My goal is to be able to spin up multiple different websocket servers & webservers and load-balance between them. I'm trying to find a reliable way to do this so that my code doesn't break... my node apps are just very frail, some direction would help. It seems like for nodejs, despite its maturity in 2017, good information lives only on stackoverflow,github issue threads and irc.freenode and I classify some of these things as basic...
packages and versions used
web-server package versions
---------------
express#4.15.2
express-session#1.15.2
mongodb#2.2.26
cookie-parser#1.4.3
body-parser#1.17.1
connect-mongodb-session#1.3.0
socket-server package versions
---------------
uws#0.14.1
below is my code
webserver.js
'use strict';
const bodyparser = require('body-parser');
const cookieparser = require('cookie-parser');
const express = require('express');
const app = express();
const express_session = require('express-session');
const connect_mongo = require('connect-mongodb-session')(express_session);
const port = process.env.NODE_WEBSERVER_PORT;
const _ = require('underscore');
const mongo_store = new connect_mongo({
uri: 'mongodb://mongo1.weave.local:27017/sessiondb',
collection: 'sess'
});
const session_time = 1000 * 60 * 5 ; // 5 minute(s)
app.use(express_session({
secret: 'superman',
cookie: {
maxAge: session_time,
httpOnly: false
},
store: mongo_store,
resave: false,
saveUninitialized: false,
name: 'inspect_the_deq',
httpOnly: false
}));
app.use(bodyparser.urlencoded({ extended: false }))
app.use(bodyparser.json());
app.set('view engine', 'pug');
app.set('views', __dirname+'/pugs')
app.use(express.static(__dirname + '/com/js'));
app.use(express.static(__dirname + '/com/asset'));
const mongo = require('mongodb').MongoClient;
const mongo_url = 'mongodb://mongo1.weave.local:27017/main';
let account = null;
let database = null;
mongo.connect(mongo_url, function(err, db) {
let collection = db.collection('account');
account = collection;
database = db;
});
app.get('/', function (req, res) {
if(req.session.user){
const user = req.session.user;
res.render('main', {message: 'user '+user+' logged in' });
console.log('session found logging you on');
}else{
res.render('login', {message: 'Login'});
console.log('no session exists');
}
});
app.post('/', function (req, res) {
const user = req.body.username, pass = req.body.password;
const seconds = session_time;
account.findOne({username: user, password: pass }, function(err, document) {
if( document !== null ){
req.session.user = user;
req.session.cookie.expires = new Date(Date.now() + seconds);
req.session.cookie.signed = true;
res.render('main', {message: 'user '+user+' logged in'});
console.log('some id is '+req.session.id);
console.log('cookie id is '+req.session.cookie);
console.log('sess id is '+req.sessionID);
}else
res.render('login', {message: 'Login', login_error: 'invalid username or password'});
});
});
app.listen(port, function () {
console.log('http server '+port);
});
Socket Server code here
'use strict';
const _ = require('underscore');
const uwsPlugin = require('uws').Server;
const socket_port = process.env.NODE_SOCKET_PORT;
const ws = new uwsPlugin({ port: socket_port, maxPayload: 0 });
//const Meepack = require('./core/meepack');
const cookieparser = require('cookie-parser');
const express_session = require('express-session');
const connect_mongo = require('connect-mongodb-session')(express_session);
const mongo_store = new connect_mongo({
uri: 'mongodb://mongo1.weave.local:27017/sessiondb',
collection: 'sess'
});
ws.on('connection', function connection(socket) {
'use strict';
console.log('client verification process ');
let headers = Object.keys(socket.upgradeReq.headers);
let upgradeReq = Object.keys(socket.upgradeReq.headers.cookie);
let cookie = socket.upgradeReq.headers.cookie;
//use the cookie here to get the session_id and do whatever you want
socket.on('close', function close(e) {
console.log('connection closed');
});
socket.on('message', function close(data) {
'use strict';
});
});
I've been having problems trying to access stored session values! Once I've set the values and try access them from a new route, I get undefined! So basically I've got a login (POST) and in that request I set the session data, and then I have a show user details (POST) where I try and access the session data I've just stored.
Setup
// Setup express and needed modules #############################################
var express = require('express'),
session = require('express-session'),
cookieParser = require('cookie-parser'),
redis = require("redis"),
redisStore = require('connect-redis')(session),
bodyParser = require('body-parser');
var client = redis.createClient(), //CREATE REDIS CLIENT
app = express();
// Setup app
app.use(cookieParser('yoursecretcode'));
app.use(session(
{
secret: 'x',
store: new redisStore({
port: 6379,
client: client
}),
saveUninitialized: true, // don't create session until something stored,
resave: false // don't save session if unmodified
}
));
app.use(bodyParser.urlencoded({ extended: true}));
app.use(bodyParser.json());
app.set('trust proxy', 1) // trust first proxy
So as you've seen my setup, you know I'm using express sessions and Redis. Below is where I'm setting the session values! If I print out the session values here it works, but then If I try and access the session data in another route it returns undefined.
Routes
I send a http post request and set the session data:
router.route('/login/').post(function(req, res) {
req.session.userId = req.body.uId;
req.session.name = req.body.uName;
// THIS PRINTS OUT IF I TRY AND ACCESS THE SESSION DATA HERE
console.log("THIS PRINTS OUT --> " + req.session.name);
});
So now that the session values have been set, I can go access them right, no, I get undefined each time I try and log them out.
router.route('/user/printoutuserdetails').post(function(req, res) {
// THESE RETURN UNDEFINED
console.log(req.session.userId);
console.log(req.session.uName);
console.log("THIS PRINTS OUT --> " + req.session.name);
});
Does anyone have any idea what's happening? I've tried everything and looked everywhere and can't seem to find a way to get it to work!
Solved:
The reason this wasn't was because you're not suppose to use sessions when using a RESTFUL api.
I'm new to NodeJS. I am developing a REST API and using express-session to deal with sessions. So, to get the session ID I'm using
var sessionID = req.sessionID
This sessionID is generated from the server side. So, when I scale up to two or more servers, this is a problem. For example, if one server shuts down and the request is redirected to another server (Assuming I have a load balancer), a new session ID is generated. So, is there a way to retrieve the session ID from the client side?
Good question! Session management can be challenging to get up and running with - especially since to get up and running with any sort of sophisticated session management in node you need a ton of different packages, each with their own set of docs. Here is an example of how you can set up session management with MongoDB:
'use strict';
var express = require('express'),
session = require('express-session'),
cookieParser = require('cookie-parser'),
mongoStore = require('connect-mongo')(session),
mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/someDB');
var app = express();
var secret = 'shhh';
app.use(session({
resave: true,
saveUninitialized: true,
secret: secret,
store: new mongoStore({
mongooseConnection: mongoose.connection,
collection: 'sessions' // default
})
}));
// ROUTES, ETC.
var port = 3000;
app.listen(port, function() {
console.log('listening on port ' + port + '.')
});
This configuration gives you access to req.sessionID but now it should persists across app servers if the user's session cookie has not expired.
I hope this works!
In node.js and express, there are many examples showing how to get session data.
Node.js and Socket.io
Express and Socket.io - Tying it all Together
Socket.io and Session?
As you can see when you visit the 3rd link, it's a link to StackOverflow. There was a good answer, but as pointed out in those comments by #UpTheCreek, connect no longer has the parseCookie method. I have just run into this problem as well. All of the tutorials I have found uses connect's parseCookie method which now doesn't exist. So I asked him how we can get the session data and he said he doesn't know the best approach so I thought I'd post the question here. When using express#3.0.0rc4, socket.io, and redis, how can we get session data and use that to authorize the user? I've been able to use require('connect').utils.parseSignedCookie;, but when I do that, I always get a warning/error when handshaking,
warn - handshake error Error
and from what I've read it sounds like that isn't a permanent solution anyways.
UPDATE
Ok I got session.socket.io working on my server. And as I suspected, I got stuck at the point of authorizing. I think I might be going about this the wrong way, so feel free to correct me. In my Redis database, I will have user's information. The first time that they login, I want to update their cookie so it contains their user information. Then the next time they come back to the site, I want to check if they have a cookie and if the user information is there. If it is not there, I want to send them to the login screen. At the login screen, when a user submits information, it would test that information against the Redis database, and if it matches, it would update the cookie with user information. My questions are these:
1) How can I update/change a cookie through RedisStore?
2) It looks like session data is saved only in cookies. How can I keep track of user information from page to page if someone has cookies turned off?
Here is my applicable code:
//...hiding unapplicable code...
var redis = require('socket.io/node_modules/redis');
var client = redis.createClient();
var RedisStore = require('connect-redis')(express);
var redis_store = new RedisStore();
var cookieParser = express.cookieParser('secret');
app.configure(function(){
//...hiding unapplicable code...
app.use(cookieParser);
app.use(express.session({secret: 'secret', store: redis_store}));
});
//...hiding code that starts the server and socket.io
var SessionSockets = require('session.socket.io');
var ssockets = new SessionSockets(io, redis_store, cookieParser);
io.configure(function(){
io.set('authorization', function(handshake, callback){
if(handshake.headers.cookie){
//var cookie = parseCookie(handshake.headers.cookie);
//if(cookie.user){
// handshake.user = cookie.user;
//}
}
callback(null, true);
});
});
ssockets.on('connection', function(err, socket, session){ ... });
Have a look at socket.io's wiki. Especially the parts Configuring Socket.IO and Authorization and handshaking.
It shows how to use socket.io with a RedisStore and gives two different authorization methods.
More information about connecting express v3, redis and socket.io
connect issue#588
socket.io and express 3
session.socket.io module
socket.io-express library
After switching to session.socket.io for a while I ran into a few problems due to the asynchronous nature of the module when loading the session information. So I ended up creating my own module called session.io. It is used like this:
var express = require('express');
var app = express();
var server = require('http').createServer(app);
//Setup cookie and session handlers
//Note: for sessionStore you can use any sessionStore module that has the .load() function
//but I personally use the module 'sessionstore' to handle my sessionStores.
var cookieParser = express.cookieParser('secret');
var sessionStore = require('sessionstore').createSessionStore();
app.configure(function(){
app.set('port', process.env.PORT || 3000);
//...truncate...//
app.use(cookieParser);
//make sure to use the same secret as you specified in your cookieParser
app.use(express.session({secret: 'secret', store: sessionStore}));
app.use(app.router);
});
app.get('/', function(req, res){
res.send('<script src="/socket.io/socket.io.js"></script><script>io.connect();</script>Connected');
});
server.listen(app.get('port'), function(){
console.log('Listening on port ' + app.get('port'));
});
var io = require('socket.io').listen(server);
io.configure(function(){
//use session.io to get our session data
io.set('authorization', require('session.io')(cookieParser, sessionStore));
});
io.on('connection', function(socket){
//we now have access to our session data like so
var session = socket.handshake.session;
console.log(session);
});
Your questions:
How can I update/change a cookie through RedisStore?
It looks like session data is saved only in cookies. How can I keep track of user information from page to page if someone has cookies turned off?
Cookies / Sessions / RedisStore Thoughts:
Typically, you have exactly one cookie, which is the session id
All user-state is stored on the server in a "session" which can be found via the session id
You can use Redis as your back-end storage for your session data.
Redis will allow you to keep session state, even when your server is restarted (good thing)
You can store a mountain of data in your session (req.session.key = value)
All data stored in the session will be persistant until the user logs out, or their session expires
Example node.js Code:
var app = express.createServer(
express.static(__dirname + '/public', { maxAge: 31557600000 }),
express.cookieParser(),
express.session({ secret: 'secret', store: new RedisStore({
host: 'myredishost',
port: 'port',
pass: 'myredispass',
db: 'dbname',
}, cookie: { maxAge: 600000 })})
);
Session and Cookie Thoughts:
Your second issue us about sessions without cookies. This is possible.
You, basically, put the session id on the url of every request you send to the server.
I strongly believe that most people allow cookies.
If this is a requirement, google: "session without cookies"
Session data is available with:
req.session