Thursday 20 April 2017

node expressjs websocket session passing

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';
    });

});



via Kid Oob

No comments:

Post a Comment