I spent 2 days on accessing sessions (log user in) trough sockets.
I already have users in my mongodb, and i can indeed login/register them without sockets (trough post or get). All i need now is the same for sockets.
I have tried these SO solutions:
socket.io and express 4 sessions
How to share sessions with Socket.IO 1.x and Express 4.x?
socket.io and session?
And spend a lot of time googling. And trying different things.
I typically get undefined errors, or deprecated error, or nothing happens at all without errors.
After following the tutorials above, and doing some tweaks myself, my code went from "hard to read" to "too hard to read, must start from scratch". So i wont put up my code here.
Instead, can someone share their bare-minimum code on what it takes to access the sessions inside sockets? With explanations would would be highly appreciated.
UPDATE
I followed this: How to share sessions with Socket.IO 1.x and Express 4.x?
And i got a few issues. It still does not work. the session is empty. Am i doing something wrong? Full code:
var express = require("express");
var Server = require("http").Server;
var session = require("express-session");
var RedisStore = require("connect-redis")(session);
var SESSION;
var app = express();
var server = Server(app);
var sio = require("socket.io")(server);
var sessionMiddleware = session({
store: new RedisStore(),
secret: "keyboard cat",
resave: true,
saveUninitialized: true
});
sio.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
app.use(sessionMiddleware);
app.get("/*", function(req, res){
SESSION = req.session
req.session.name="THE NAME"; // <<<< SHOULDN'T THIS WORK? ITS UNDEFINED
if(req.path=="/"){
res.sendFile(__dirname+"/index.html");
}else{
res.sendFile(__dirname+req.path);
};
});
sio.sockets.on("connection", function(socket) {
SESSION = socket.request.session
console.log("The SESSION variable on socket connection:");
console.log(SESSION); //<<<<<<<<<<<< UNDEFINED
socket.on("get session status",function(){
socket.emit("session status",{ SESSION:SESSION }); // <<<<< EMPTY OBJECT
})
});
server.listen(80);
The accepted answer at the second link works fine for me:
app.js:
var session = require("express-session");
var app = require('express')();
var server = require('http').Server(app);
var io = require('socket.io')(server);
var sessionMiddleware = session({
secret: "keyboard cat",
resave: true,
saveUninitialized: true
});
app.use(sessionMiddleware);
app.use(function(req, res) {
req.session.name = "THE NAME";
res.sendFile(__dirname + "/index.html");
});
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
io.on("connection", function(socket) {
console.log('socket.io connection');
console.dir(socket.request.session);
// above outputs:
// socket.io connection
// { cookie:
// { path: '/',
// _expires: null,
// originalMaxAge: null,
// httpOnly: true },
// name: 'THE NAME' }
});
server.listen(8000);
index.html:
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io.connect('http://localhost:8000');
</script>
Perhaps there is an issue with timing where the session data isn't saved to Redis yet when the socket.io connection is made? You might try delaying the socket.io connection at least until the page is fully rendered (window.onload).
Related
I am facing an issue with handling session using latest version of Express, Node.js.
My requirement is to store users email id in /login route, and need to get that email id thought out
all routes like /home. But email id is not printing in /home route with my current code. Your help is much appreciate.
My demo code is here
var express = require('express');
var app = express();
var cookieParser = require('cookie-parser');
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
app.set('port',process.env.PORT || 3000);
app.use(cookieParser());
app.use(session({
resave: false,
saveUninitialized: false,
store: new RedisStore({
host: 'localhost',
port: 6379
}),
secret: 'some string/hash secret'
}));
var counter=0;
app.get('/login', function(request, response){
//adding some value to request.session
request.session.email = 'jak#amt.in';
console.log('sessionID', request.sessionID)
response.send('email: '+request.session.email);
});
app.get('/home', function (request, response) {
console.log('home login', request.session.email); // Email not priting here
console.log('sessionID - home', request.sessionID); // Session ID is showing
response.send('home');
});
if (!module.parent) {
console.info('Listening ', process.env.PORT || 5000);
app.listen(process.env.PORT || 5000);
}
module.exports = app;
I am getting following error
"ReplyError: ERR wrong number of arguments for 'set' command
at parseError (/home/dibeesh/obpnode6/testproject/node_modules/redis/node_modules/redis-parser/lib/parser.js:161:12)
at parseType (/home/dibeesh/obpnode6/testproject/node_modules/redis/node_modules/redis-parser/lib/parser.js:222:14)"
Make sure your redis server is running when you run your app.
I have application which use node.js and socket.io.
I would like store some information in session. I made example. But my code doesn't work. When I run my script and refresh page I see:
NaN
2
Next, when I refresh page again I can see
NaN
2
NaN
2
So session is not stored. How can I fix my code ?
var Session = require('express-session'),
SessionStore = require('session-file-store')(Session);
var session = Session({ secret: 'pass', resave: true, saveUninitialized: true });
var config = require("./config.json");
var express = require('express');
var app = express();
var socketio = require('socket.io');
var server = app.listen(3000, function(){
console.log('Start')
});
var io = require('socket.io').listen(server);
app.use(session); // session support
app.get('/', function (req, res) {
req.session.ziom = 1;
req.session.save();
console.log('dec');
});
var http = require('http');
var ios = require('socket.io-express-session');
io.use(ios(session));
io.sockets.on('connection', function(socket){
console.log(parseInt(socket.handshake.session.test));
socket.handshake.session.test =2;
socket.handshake.session.save();
console.log(parseInt(socket.handshake.session.test));
});
I dont't understand this error because I copy-past your code and everything* work fine !
*I can't see all your code/project, I don't know if you have an index.html file who start connexion event with the node server. I had this file with minimum code for test.
Change in my app.js is res.sendfile('./index.html');
See all my code below for comparison.
app.js
var Session = require('express-session'),
SessionStore = require('session-file-store')(Session);
var session = Session({ secret: 'pass', resave: true, saveUninitialized: true });
var express = require('express');
var app = express();
var socketio = require('socket.io');
var server = app.listen(3000, function(){
console.log('Start')
});
var io = require('socket.io').listen(server);
app.use(session); // session support
app.get('/', function (req, res) {
req.session.ziom = 1;
req.session.save();
console.log('dec');
res.sendfile('./index.html');
});
var http = require('http');
var ios = require('socket.io-express-session');
io.use(ios(session));
io.sockets.on('connection', function(socket){
console.log(parseInt(socket.handshake.session.test));
socket.handshake.session.test =2;
socket.handshake.session.save();
console.log(parseInt(socket.handshake.session.test));
});
index.html
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<script src="https://cdn.socket.io/socket.io-1.3.5.js"></script>
<script>
var socket = io();
</script>
</body>
</html>
Sincerely hope that helps.
I assume you're trying to open the socket.io connection using an HTML file similar to the bootstrap file in the tutorial (second html snippet after this link)?
With a small change, your code worked for me, where working means you get
NaN
2
2
2
on the console with two page refreshes.
In order to get this, I created the boostrap file relative to the index.js file (a copy of your code above) at views/socket.html, and ensured this was served by the express app by adding these lines to the handler for the '/' route:
require('fs').readFile('views/socket.html', function (err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data, "utf8");
res.end();
});
Then visited http://localhost:3000 twice.
It is required for this file to be served by the express app in order for the session cookie to be stored; so that the socket.io connection knows to use the same cookie to be linked to the same session at the next refresh.
https://github.com/xpepermint/socket.io-express-session
This is one of many ways i tried.
I tried all of these answers as well:
How to share sessions with Socket.IO 1.x and Express 4.x?
And some more...It all gives me the exaclty same result:
throw new TypeError("Parameter 'url' must be a string, not " + typeof
url)
^ TypeError: Parameter 'url' must be a string, not undefined
I already tried every solution i found on the internet, basically everything leads me to the same error.
At some point i simply tried copying and pasting examples found and they give me the exactly same results.
I guess something went wrong after one of the middleware updates. How to fix it? Is there another, reliable way to share express session with socket.io?
var Session = require('express-session');
var session = Session({ secret: 'pass', resave: true, saveUninitialized: true });
var cookieParser = require('cookie-parser');
var express = require('express');
var app = express();
app.use(cookieParser());
app.use(session); // session support
app.get('/', function (req, res) {
req.session.uid = 1;
res.send('Hi user #' + req.session.uid);
});
var http = require('http').createServer(app);
http.listen(3000, function(){
console.log('listening on *:3000');
});
var ios = require('socket.io-express-session');
var io = require('socket.io')(http);
io.use(ios(session)); // session support
io.on('connection', function(socket){
console.log(socket.handshake.session);
});
Above is an example returning exactly this error.
The error occurs in the stage when you use io.use(...)
The problem is that session middle ware expects to find the session in req.orginalUrl. A socket does not have an orginalUrl. To fix this, simply assign one...
io.use(function(socket, next){
socket.request.originalUrl = socket.request.url;
session(socket.request, socket.request.res, next);
});
The next problem is going to be that session(...) expects the cookies to be parsed. We can use 'cookie-parser' for this:
var cookieParse = cookieParser();
io.use(function(socket, next){
cookieParse(socket.request, socket.request.res, next);
});
After that we can simply bridge passport and socket.io:
var passInit = passport.initialize();
var passSess = passport.session();
io.use(function(socket, next){
passInit(socket.request, socket.request.res, next);
});
io.use(function(socket, next){
passSess(socket.request, socket.request.res, next);
});
Now in our io.on('connection') we can see socket.request.user
io.on('connection', function(socket){
console.log("socket connection");
console.log(socket.request.user)
console.log(socket.request.session.passport.user);
});
Using Bradley Lederholz's answer, this is how I made it work for myself. Please refer to Bradley Lederholz's answer, for more explanation.
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io');
var cookieParse = require('cookie-parser')();
var passport = require('passport');
var passportInit = passport.initialize();
var passportSession = passport.session();
var session = require('express-session');
var mongoStore = require('connect-mongo')(session);
var mongoose = require('mongoose');
var sessionMiddleware = session({
secret: 'some secret',
key: 'express.sid',
resave: true,
httpOnly: true,
secure: true,
ephemeral: true,
saveUninitialized: true,
cookie: {},
store:new mongoStore({
mongooseConnection: mongoose.connection,
db: 'mydb'
});
});
app.use(sessionMiddleware);
io = io(server);
io.use(function(socket, next){
socket.client.request.originalUrl = socket.client.request.url;
cookieParse(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
socket.client.request.originalUrl = socket.client.request.url;
sessionMiddleware(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
passportInit(socket.client.request, socket.client.request.res, next);
});
io.use(function(socket, next){
passportSession(socket.client.request, socket.client.request.res, next);
});
io.on('connection', function(socket){
...
});
...
server.listen(8000);
I have a Node.js server using express framework with a session system. The program is a simple 1vs1 game. In order to play, a user can create a room and an other user can join it so the game can start. The room ID is stored into the user's session.
If you take a look at the following code, you'll see how I manage to access express sessions in a "socket code". This is great, it works. However, I cannot modify values in the session object.
var express = require('express');
var session = require('express-session');
var sessionMiddleware = session({
secret: 'my secret',
resave: false,
saveUninitialized: false
});
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
app.use(sessionMiddleware);
io.use(function(socket, next) {
sessionMiddleware(socket.request, socket.request.res, next);
});
io.on('connection', function(socket) {
// some stuff
socket.on('disconnect', function() {
socket.request.session.room = undefined; // this is not working
});
});
server.listen(8080);
Is there a way to do what I want or should I rethink the way rooms are managed ?
Thank you
I'm a Node-beginner and have the following problem. I use express, socket.io and passport as well as passport.socketio and a MongoStore.
I need to authenticate socket.io with passport (I use passport.socketio for this), but the handshake is always unauthorized even after successfull login. Here is my code so far:
var http = require('http')
var socketio = require('socket.io')
var express = require('express')
var stylus = require('stylus')
var passport = require('passport')
var passportSocketIo = require('passport.socketio')
var LocalStrategy = require('passport-local').Strategy
var mongo = require('mongoskin')
var MongoStore = require('connect-mongo')(express)
var DB = mongo.db('mongo://127.0.0.1/accounts', {safe:false})
DB.bind('accounts')
DB.bind('SessionStore')
SessionStore = new MongoStore({ db: 'SessionStore' })
var app = express()
app.configure(function () {
app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.cookieParser())
app.use(express.bodyParser())
app.use(express.session({
secret: 'somekey',
store: SessionStore
}));
app.use(passport.initialize())
app.use(passport.session())
app.use(app.router)
})
Here is where I login:
app.post('/login', passport.authenticate('local', { successRedirect: '/',
failureRedirect: '/login_failed',
failureFlash: false }))
And here I try to access a page ('/content'), for which I need authorization:
app.get('/content', ensureAuthenticated, function(req, res){
res.render('content', { user: req.user })
})
var server = http.createServer(app).listen(5050)
var io = socketio.listen(server)
io.set('authorization', passportSocketIo.authorize({
cookieParser: express.cookieParser,
key: 'express.sid',
secret: 'somekey',
store: SessionStore,
fail: function(data, accept) {
accept(null, false);
},
success: function(data, accept) {
accept(null, true);
}
}))
But if a client now tries to access '/content', the server always responds 'handshake unauthorized':
// on client side
socket = io.connect('http://localhost:5050');
// on server side
io.sockets.on( 'connection', function( socket ) {
console.log(socket.handshake.user._id)
}
-> handshake unauthorized
Does anyone know what I do wrong here?
Yes that's an issue known since two years and not resolve yet :
https://github.com/LearnBoost/socket.io/issues/545
As koenigsbier said in this github issue :
In my client side I had var socket =
io.connect('http://localhost:8080'); and it's works only if you put
localhost:8080 in your browser.
I changed it by var socket = io.connect('http://127.0.0.1:8080');
and now it works with localhost:8080 and 127.0.0.1:8080 in your
browser.
It's clearly a bug, why socket.io should accept address mapping just
in one way? localhost is localhost and is the same as 127.0.0.1
On client side, try to put 127.0.0.1 instead of localhost
You need to use:
key: 'connect.sid',
instead of
key: 'express.sid',
for the key. Check out the cookie in your browser, you won't see express.sid, but connect.sid will have a value. The only other difference that I see between yours and my working example is I set a var to express.cookieParser and then use that both in app config and in io.set authorization.
var cookieParser = express.cookieParser();