在CORS呼叫之后,Express Session不会持久

TL; DR:

在Express,Express-Session和Express-Cors之间的骨干应用程序和Node.js服务器之间执行跨多个API的持久会话不能成功。 看起来每次通话之后会话都会重新初始化/丢失。

长版本:

我有一个运行在localhost:3000上的客户端Backbone / React / Flux应用程序,在运行在localhost:4242上的Node.js服务器上执行以下调用:

Http调用

POST http:// localhost:4242 / api / session

  RESPONSE HEADERS Content-Type application/json; charset=utf-8 Set-Cookie connect.sid=s%3AFeNYY5GQGvkyRvOym7DhysprePaQr7xP.BrxOPP56k9pDpxQPvwjDFaxkEYoHU%2FAEtNUIXGltqjI; Domain=http://localhost:3000; Path=/ Vary Origin X-Powered-By Express access-control-allow-credentials true access-control-allow-orign http://localhost:3000 [...] REQUEST HEADERS Accept application/json, text/javascript, */*; q=0.01 Content-Type application/json; charset=utf-8 Cookie connect.sid=s%3AjP4iADZvRnDHbJcCE8H81Zy6TIehj9BJ.eDOTw44GcHqq8i2dslBGd43tXMQ22ENl31fRizdC8iA Host localhost:4242 Origin http://localhost:3000 Referer http://localhost:3000/login [...] 

GET http:// localhost:4242 / api / users

  RESPONSE HEADERS Content-Type application/json; charset=utf-8 Set-Cookie connect.sid=s%3ARxf91_vLMBqzB6xN-0QFIIk_-SyBP9_8.F1Mr%2BVSkYNJ6MqnzO%2BsxxfwXRinIX6th80SoukG1QBM;Domain=http://localhost:3000; Path=/ Vary Origin X-Powered-By Express access-control-allow-credentials true access-control-allow-orign http://localhost:3000 [...] REQUEST HEADERS Accept application/json, text/javascript, */*; q=0.01 Content-Type application/json; charset=utf-8 Cookie connect.sid=s%3AjP4iADZvRnDHbJcCE8H81Zy6TIehj9BJ.eDOTw44GcHqq8i2dslBGd43tXMQ22ENl31fRizdC8iA Host localhost:4242 Origin http://localhost:3000 Referer http://localhost:3000/login [...] 

基本上,第一个调用POST /api/session正在login用户,并尝试在会话中存储一个API令牌。 第二次调用GET /api/users在第一次成功后触发,并检索用户信息。

骨干方法

以下是Session模型中用于login的Backbone方法:

  login: (options) -> @set {user: options.user, password: options.password} @save ['user', 'password'], success: (data) => @set({authenticated: true, accessToken: data.accessToken, password: null}) options.success(data) # trigger the second call here error: (error) => options.error(error) 

并调用我的UserStore中的/ api /用户

 users: (options) -> @users.fetch success: (users) => @users = users options.success(users) 

使用这些不同的选项(我已经重写了Backbone.Collection / Backbone.Model中的Backbone.sync):

 class UsersCollection extends Backbone.Collection url: '/api/users' model: UserModel sync: (method, model, options) -> options ?= {} options.url ?= @url options.dataType ?= 'json' options.contentType ?= "application/json; charset=utf-8" options.crossDomain ?= true options.xhrFields ?= {"withCredentials": true} super(method, model, options) 

(简化版本:对于模型和集合,使用BaseCollection和BaseModel,我将覆盖sync()方法)。

所以Backbone.sync(method, model, options)中的Console.log(options)返回:

 {"url":"http://localhost:4242/api/session","dataType":"json","contentType":"application/json; charset=utf-8","crossDomain":true,"validate":true,"parse":true,"xhrFields":{"withCredentials":true}} 

Node.js设置和方法

这里是我的Node.js路由器设置快速:

 BodyParser = require 'body-parser' Session = require 'express-session' Cors = require 'cors' class Router constructor: (express) -> @express = express @express.use BodyParser.json() @express.use Cors(@corsConfig()) @express.use Session(@sessionConfig()) # Express routes are set here # @express.post '/api/session', (request, response) => [...] # @express.get '/api/users', (request, response) => [...] corsConfig: -> origin: 'http://localhost:3000' credentials: true sessionConfig: -> secret: 'whatever' cookie: secure: false httpOnly: false domain: 'http://localhost:3000' 

这里是我的Node.js方法处理POST /api/session

  login: (request, response) -> session = request.session console.log JSON.stringify(session) console.log request.sessionID console.log '---------------------------------------------' if session.accessToken console.log 'session with token!' response.json {accessToken: session.accessToken} else console.log 'performing credentialAuthentication' user = request.body.user password = request.body.password @whatever.authentication user: user password: password success: (accessToken) -> request.session.accessToken = accessToken console.log JSON.stringify(session) console.log request.sessionID console.log '---------------------------------------------!!!' response.json {accessToken: accessToken} # also tried with response.send() 

还有一个处理GET /api/users

  @express.get '/api/users', (request, response) => console.log JSON.stringify(request.session) console.log request.sessionID console.log '---------------------------------------------' [...] 

Node.js日志

这里是日志:

  express:router dispatching OPTIONS /api/session express:router dispatching POST /api/session {"cookie":{"originalMaxAge":null,"expires":null,"secure":false,"httpOnly":false,"path":"/"}} zse18d2zrNRdEXPjFHF0gm3NkONb-_5V --------------------------------------------- performing credentialAuthentication {"cookie":{"originalMaxAge":null,"expires":null,"secure":false,"httpOnly":false,"path":"/"}, "accessToken":"ebab5010f9ece5ea984e4b73f9a46ef3"} zse18d2zrNRdEXPjFHF0gm3NkONb-_5V ---------------------------------------------!!! express:router dispatching GET /api/users {"cookie":{"originalMaxAge":null,"expires":null,"secure":false,"httpOnly":false,"path":"/"}} g8YXQEpt_rnWSGdh1nCKMndiI8Lt2UDq --------------------------------------------- 

正如你所看到的CORS请求正常执行,我正确地得到我的令牌,然后尝试将其存储在会话中。

但是在第二次调用中,会话不会被持久化,而且我无法访问实际上在第一次调用中设置的variables(accessToken)。

查看两个调用的日志和HTTP Headers,看起来会话每次都会重新初始化,因为会话ID正在改变,每个请求都会发生,并且每次都会发送一个Set-Request头据我所知,情况就是如此)。

我怀疑这种行为是由CORS级别的一些不连贯或缺失的configuration引起的,或者是由于Sessions( Express.use(path, middleware)Cookie({path: '/'}) )的path设置造成的。 但是,尽pipe尝试不同的configuration,设置和标题,我真的无法使其工作。

任何人都可以启发我的这种行为,我所缺less的是非常欢迎:)
谢谢!

PS:我向非CoffeeScript开发者道歉;)

答案如下(简单的一个):我错误configuration了会话中间件; cookie.domain选项导致了问题。 这是正确的configuration:

 sessionConfig: -> secret: 'whatever' cookie: secure: false httpOnly: false 

快速/会话中间件不需要/不存在此选项; 不知道为什么我最初使用它,可能是过时的引用(expression式/ cookie分析器或express / cors)。