与 socket.io 一起使用时 express-session 未设置会话 cookie

Posted

技术标签:

【中文标题】与 socket.io 一起使用时 express-session 未设置会话 cookie【英文标题】:express-session isn't setting session cookie while using with socket.io 【发布时间】:2016-02-28 01:56:14 【问题描述】:

我正在尝试使用 socket.io 实现身份验证和会话。

经过大量研究1,我设置了以下使用express和express-session。

问题在于,express 和 socket.io 连接似乎具有不同的会话,因为我得到的 id 不同。

另外,我的应用程序没有在浏览器中设置 cookie(这可能是两个组件创建不同会话的原因?)

我正在使用 express 4.13.3 express-session 1.12.1 和 socket.io 1.3.7

下面是我设置的服务器端代码:

var app = require('express')();
var server = app.listen(80);
var parser = require('body-parser');
var Session = require('express-session');
var io = require('socket.io')(server);
var game = require('./game.js');
var session = Session(
  secret: 'some secret',
  resave: false,
  saveUninitialized: false,
  cookie: 
    'name': 'test',
    httpOnly: false,
    secure: false,
    maxAge: ((60 * 1000) * 60)
  
);
app.use(parser.urlencoded(
  extended: false
));
app.use(session);
app.use(function(req, res, next) 
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  next();
);
app.post('/login', function(req, res) 
  console.log('login %s', req.session.id);
  console.dir(req.session, 
    color: true
  );
  res.json(
    status: 'success'
  );
);
io.use(function(socket, next) 
  session(socket.handshake, , next);
);
console.log('socket server started @ %s !', 80);
io.on('connection', function(socket) 
  console.log('user connected %s', socket.handshake.session.id);
  console.dir(socket.handshake.session, 
    color: true
  );
  socket.on('disconnect', function() 
    console.log('user disconnected');
    console.dir(socket.handshake.session, 
      color: true
    );
  );
);

以及用于测试目的的客户端代码:

$.ajax(
   url: 'http://127.0.0.1:80/login',
   type:'post',
   success: function(response) 
      var socket = io('http://127.0.0.1:80');
   
);

下面是控制台的输出:

这是浏览器中的资源部分:

看到session 对象在登录控制台时没有任何id 属性,我什至感到困惑,但session.id 打印出不同的值。也许这来自对象原型链或其他东西。

我能想到的关于我的代码和教程的唯一区别是,它们都从同一个快速服务器提供index.html 页面。就我而言,我在本地有文件。

我在某处读到,在这种情况下,我必须在建立 socket.io 连接之前发送http 请求来表达。

socket.io.js 客户端库由 express 和 socket.io (<script src="http://127.0.0.1/socket.io/socket.io.js"></script>) 共享的同一服务器提供服务,除此之外,我还在使用 express 路由 /login 进行测试之前套接字连接已建立。

所以我想知道为什么没有在客户端设置 cookie,以及为什么 express 和 socket 请求创建了不同的会话..?我在这里想念什么..?


1 代码大多基于:

How to share sessions with Socket.IO 1.x and Express 4.x? socket.io and session?

P.S:我想要做的是,当套接字客户端重新连接时,我需要将他放回他所在的位置,并提供会话详细信息。我真的不想与 express 共享会话,但 express 中间件是我遇到的使用 socket.io 实现会话的唯一方法。

【问题讨论】:

【参考方案1】:

问题与 express 或 socket.io 无关。问题是,我是从本地服务器而不是 express 和 socket.io 服务器加载项目。

所以这是一个跨域 ajax 请求,在这种情况下,一些浏览器拒绝处理 Set-Cookie 标头。我们可以通过在 answer 中提到的 ajax 选项中添加以下内容来解决此问题:

xhrFields: 
   withCredentials: true
,

或者,如果您正在使用 Angular,请发送withCredentials: true 喜欢

$http(withCredentials: true, ...).get(...) 如在此answer 中所述。

在服务器端,设置此标头:

res.header("Access-Control-Allow-Credentials", 'true');

如果您添加它,chrome 将不再允许您在 Access-Control-Allow-Origin 标头中使用通配符 *。您还应该将其设置为特定的允许域。

res.header("Access-Control-Allow-Origin", "allowed domains");

【讨论】:

【参考方案2】:

你不应该

res.session.save(); // add this line
res.json( status: 'success' ); // or just res.send(status:success);

?

此外,我有点建议您为此目的使用passport module 和passport-local 策略,这样您就不必为您的会话不起作用而烦恼。一旦它为我节省了很多时间。

【讨论】:

以上是关于与 socket.io 一起使用时 express-session 未设置会话 cookie的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Socket.io 和 Express 进行集群

无法让 JWT 身份验证与 socket.io 一起使用

带有 socket.io 和 express 的 Websocket

如何使用 socket io 和 node express 发送个人消息

Socket.io 1.0 + express 4.2 = 无套接字连接

如何在用户从帐户注销时断开事件触发(node.js + express socket.io)