Connect.sid始终未定义,req.session ID保持重置

时间:2014-05-25 21:34:48

标签: node.js angularjs session cookies redis

我对NodeJS / Express / Socket.IO很新,并且使用Socket.IO通信制作了一个简单的摇滚剪刀应用程序(在客户端我使用的是AngularJS)。到目前为止,应用程序的这一部分工作得非常好。

但是,我开始使用Redis实现会话,并偶然发现了一些问题。因为我这样做是为了学习,所以我决定使用套接字(使用石头剪刀游戏的整个实时部分)来完成应用程序的一部分,而另一部分则不需要真正的-time组件使用常规REST(排行榜,查看其他人的个人资料等)。

我遇到的问题是从未在客户端上设置connect.sid cookie。我做了一个简单的checkSession REST调用来测试会话是否持久化,但似乎不是。我在checkSession电话中注意到的是req.sessionID总是给我一个全新的会话ID。现在,我不确定我是否应该手动创建connect.sid,或者节点是否应该自动处理?如果我应该这样做,我应该怎么做? “set authorization”回调在握手对象中也永远不会有connect.sid cookie。

另外,根据我在研究过程中的内容,在常规REST(Express)和Socket.IO之间共享会话可能会有点麻烦。这是我的代码(我关闭了整个摇滚剪刀逻辑,以确保不是导致问题的原因)。

package.json

{
  "name": "RPSLS.Node",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "start": "node app.js"
  },
  "dependencies": {
    "express": "3.5.1",
    "session": "0.1.0",
    "socket.io": "0.9.16",
    "redis": "0.10.2",
    "connect-redis": "1.4.7"
  }
}

app.js

var express = require('express');
var parseCookie = express.cookieParser("megaultrasupersecret");

var http = require('http');
var path = require('path');
var io = require('socket.io');

var app = express();
var server = http.createServer(app);
var ioServer = io.listen(server);

var redis = require('redis');
var RedisStore = require('connect-redis')(express);

// Route dependencies
var sharedData = require('./shared/data')();
var routes = require('./routes');

// Enable CORS
var allowCrossDomain = function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "http://rpsls.local" || "http://localhost" || "http://127.0.0.1");
    res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
    res.header("Access-Control-Allow-Headers", "Content-Type");
    next();
}

// All environments
app.set('port', process.env.PORT || 7331);
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.cookieParser("megaultrasupersecret"));
app.use(express.session({ store: new RedisStore({ client: redis.createClient() }), key: "connect.sid", secret: "megaultrasupersecret", cookie: { maxAge: 24 * 60 * 60 * 1000 } }));
app.use(allowCrossDomain);
app.use(app.router);

ioServer.configure(function () {
    ioServer.set('store', new io.RedisStore({
        redisPub: redis.createClient(),
        redisSub: redis.createClient(),
        redisClient: redis.createClient()
    }));

    ioServer.set('authorization', function (handshakeData, callback) {
        console.log(handshakeData.headers.cookie); // always returns undefined

        parseCookie(handshakeData, null, function (err) {
            // both always returns undefined
            console.log(handshakeData.signedCookies['connect.sid']);
            console.log(handshakeData.cookies['connect.sid']);
        });

        callback(null, true); // error first callback style 
    });
});

app.get("/", routes.index);
app.get("/checkSession", routes.checkSession);

ioServer.sockets.on('connection', function (socket) {
    // ... socket logic ... 
});

server.listen(app.get('port'), function(){
    console.log("Express server listening on port " + app.get('port'));
});

checkSession实施:

module.exports = function () {
    return {
        index: function (req, res) {
            res.send("RPSLS.Node API is online.");
        },
        checkSession: function (req, res) {
            console.log("----------- SESSION:   ");
            console.log(req.session);
            console.log("----------- Session ID:   " + req.sessionID); // always a brand new sessionID
            console.log("----------- Session UserName:   " + req.session.userName); // never gets persisted
            console.log("----------- Connect.sid:   " + req.cookies["connect.sid"]); // always undefined
            console.log("----------- REQ cookies:   "); 
            console.log(req.cookies); // sometimes outputs some _ga cookie (have no clue what it's for), but nothing else

            req.session.userName = "someUserName";
            req.session.save(function () {
                res.send("TEST");
            });
        }
    };
};

console.log输出:

----------- SESSION (this is what gets stored in redis):
{ cookie:
   { path: '/',
     _expires: Mon May 26 2014 22:56:23 GMT+0200 (Central European Daylight Time),
     originalMaxAge: 86400000,
     httpOnly: true } }
----------- Session ID:   7KIjYzdqfyZFCjDDT4bE1P5a
----------- Session UserName:   undefined
----------- Connect.sid:   undefined
----------- REQ cookies:  {}

Angular HTTP调用:

this.checkSession = function () {
    $http.get('http://localhost:7331/checkSession')
        .success(function (userName) {
            console.log(userName);
        });
};

以下是来自Redis的一些密钥,以确认它是否正常工作(我还成功地将一些其他数据保存到应用程序的其他部分的Redis中,但认为这与此无关):

127.0.0.1:6379> keys *
sess:Fe8ND2riR4jQEtCEmhYKi4hS
sess:WGLNkth7HW2PtR2AG4noId8Q
sess:Ph0aUwRWEtawEWxIrqVQj3Us
sess:RzLVnaLV8BPZqUsjCCzV9RCn
sess:ZfmMcGUyFf957IsVc1gkbXKb
sess:6zdD3PStbx1EmFtHjoxmVGkr
sess:QNyHy4PUNE21fBrgmjiyjNkq

我在DevTools中注意到的另一件事是名为connect.sid的响应cookie,其中包含会话ID和散列密码。此会话ID始终是我在checkSession中获得的新会话ID。我应该手动在客户端上设置它,还是应该开箱即用?

enter image description here

这是来自回复标题:

Set-Cookie:connect.sid=s%3AvMXrIBuaheA7ZBkxql51HQfO.67KqBFY4DVS4rQ50jv2B6bn4V6LeLMpdMxcpP6P%2FXIc;
Path=/; Expires=Mon, 26 May 2014 21:19:05 GMT; HttpOnly

我花了很多时间试图解决这个问题,但我仍然无法理解为什么这不起作用。一切都在localhost上运行。我不理解和做错什么,我错过了什么?

edit1: 根据mscdex的请求,console.dir(req.headers)输出以下内容:

{ host: 'localhost:7331',
  'user-agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0', accept: 'application/json, text/plain, */*',
  'accept-language': 'en-US,en;q=0.5',
  'accept-encoding': 'gzip, deflate',
  dnt: '1',
  referer: 'http://localhost:9000/',
  origin: 'http://localhost:9000',
  connection: 'keep-alive',
  'if-none-match': '"-286616648"',
  'cache-control': 'max-age=0' }

edit2: 如果它具有任何重要性,NodeJS应用程序正在localhost:7331上运行,我尝试在localhost:9000上运行AngularJS(通过grunt ),127.0.0.1:9000rpsls.local(通过MS IIS)具有相同的结果。

1 个答案:

答案 0 :(得分:4)

尝试将res.header("Access-Control-Allow-Credentials", "true");添加到allowCrossDomain中间件功能中。您也可以考虑使用cors中间件而不是自己处理CORS。

然后修改您的角度来电,将withCredentials: true添加到请求配置中:$http.get('http://localhost:7331/checkSession', { withCredentials: true })