I\'m trying to make a chat application based on Node.js. I\'d like to force websocket server (ws library) to using ExpressJS session system. Unfortunately, I\'ve got stuck.
I found this works for me. Not sure it's the best way to do this though. First, initialize your express application:
// whatever your express app is using here...
var session = require("express-session");
var sessionParser = session({
store: session_store,
cookie: {secure: true, maxAge: null, httpOnly: true}
});
app.use(sessionParser);
Now, explicitly call the session middleware from the WS connection. If you're using the express-session
module, the middleware will parse the cookies by itself. Otherwise, you might need to send it through your cookie-parsing middleware first.
If you're using the websocket
module:
ws.on("request", function(req){
sessionParser(req.httpRequest, {}, function(){
console.log(req.httpRequest.session);
// do stuff with the session here
});
});
If you're using the ws
module:
ws.on("connection", function(req){
sessionParser(req.upgradeReq, {}, function(){
console.log(req.upgradeReq.session);
// do stuff with the session here
});
});
For your convenience, here is a fully working example, using express
, express-session
, and ws
:
var app = require('express')();
var server = require("http").createServer(app);
var sessionParser = require('express-session')({
secret:"secret",
resave: true,
saveUninitialized: true
});
app.use(sessionParser);
app.get("*", function(req, res, next) {
req.session.working = "yes!";
res.send("<script>var ws = new WebSocket('ws://localhost:3000');</script>");
});
var ws = new require("ws").Server({server: server});
ws.on("connection", function connection(req) {
sessionParser(req.upgradeReq, {}, function(){
console.log("New websocket connection:");
var sess = req.upgradeReq.session;
console.log("working = " + sess.working);
});
});
server.listen(3000);
In version 3.2.0 of ws
you have to do it a bit differently.
There is a full working example of express session parsing in the ws
repo, specifically using a new feature verifyClient
.
A very brief usage summary:
const sessionParser = session({
saveUninitialized: false,
secret: '$eCuRiTy',
resave: false
})
const server = http.createServer(app)
const wss = new WebSocket.Server({
verifyClient: (info, done) => {
console.log('Parsing session from request...')
sessionParser(info.req, {}, () => {
console.log('Session is parsed!')
done(info.req.session.userId)
})
},
server
})
wss.on('connection', (ws, req) => {
ws.on('message', (message) => {
console.log(`WS message ${message} from user ${req.session.userId}`)
})
})
I was able to get this working. I think you need to specify the secret on cookieParser instead of session store.
Example from my app:
var app = express();
var RedisStore = require('connect-redis')(express);
var sessionStore = new RedisStore();
var cookieParser = express.cookieParser('some secret');
app.use(cookieParser);
app.use(express.session({store: sessionStore}));
wss.on('connection', function(rawSocket) {
cookieParser(rawSocket.upgradeReq, null, function(err) {
var sessionID = rawSocket.upgradeReq.signedCookies['connect.sid'];
sessionStore.get(sessionID, function(err, sess) {
console.log(sess);
});
});
});
WS v3.0.0 and above, has changed the behaviour so the given answers won't work out of the box for those versions. For current versions, the signature of the connection method is [function(socket, request)] and the socket no longer contains a reference to the request.
ws.on(
'connection',
function (socket, req)
{
sessionParser(
req,
{},
function()
{
console.log(req.session);
}
);
}
);
Currently, below is my workaround which is working fine. I just don't know it's disadvantages and security. I just prevent the server from listening if it doesn't have a session. (Share session from express-session to ws)
I haven't fully tested this though.
var http = require('http');
var express = require('express');
var expressSession = require('express-session');
var router = express.Router();
var app = express();
const server = http.createServer(app);
router.get('/', function(req, res, next) {
if(req.session.user_id) {
// Socket authenticated
server.listen(8080, function listening(){});
}
});