CORS通话后,Express Session无法持续 [英] Express Session not persisting after CORS calls
问题描述
TL; DR:
无法成功执行多个API调用之间的持久会话在Backbone App和带有Express的Node.js服务器之间,Express-Session和Express-Cors.会话似乎已重新初始化/丢失每次通话后.
Can't succeed persisting session across multiple APIs call performed between a Backbone App and Node.js Server with Express, Express-Session and Express-Cors. Looks like session is reinitialized/lost after every call.
长版:
我有一个运行在 localhost:3000
上的客户端Backbone/React/Flux应用程序,在运行在 localhost:4242
上的Node.js服务器上执行以下调用:
I'm having a client Backbone/React/Flux application running on localhost:3000
performing the following call on a Node.js server running on localhost:4242
:
Http呼叫
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
[...]
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
是登录用户并尝试在会话中存储API令牌.第一个调用 GET/api/users
在第一个调用成功后立即触发,并检索用户信息.
Basically the first call POST /api/session
is logging-in the user and attempting to store an API token in the session.
Second call GET /api/users
is triggered right after the first one succeed, and retrieving user information.
骨干方法
这是用于登录的Session模型上的Backbone方法:
Here's my Backbone method on the Session model for logging-in :
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的调用
And the call to /api/users in my UserStore
users: (options) ->
@users.fetch
success: (users) =>
@users = users
options.success(users)
使用这些不同的选项(我已经在Backbone.Collection/Backbone.Model中覆盖了Backbone.sync):
Using those different options (I've overridden Backbone.sync in Backbone.Collection/Backbone.Model):
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的Model和Collection都是相同的,在这里我覆盖了sync()方法).
(Simplified version: same thing for both Models and Collection, using BaseCollection and BaseModel, where I am overridding the sync() method).
因此 Backbone.sync(方法,模型,选项)
中的 Console.log(选项)
正在返回:
{"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路由器设置Express:
Here's my Node.js router setting-up Express :
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
Here's my Node.js method handling 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请求正在正常执行,我正在正确获取令牌,然后尝试将其存储在会话中.
As you can see the CORS request is performing normally, I am properly getting my token and then attempting to store it within the session.
但是,在第二个呼叫中该会话没有持久化,并且我无法访问我在第一个呼叫中实际设置的变量(accessToken).
查看两个调用的日志和HTTP标头,看起来每次会话都被重新初始化,因为会话ID不断变化,每个请求都有-并且每次都发送一个Set-Request标头(据我了解,情况并非如此).
Looking at the log and at the HTTP Headers of the two call, it looks like the session is reinitialized each time, as the session ID is changing and each request - and there is a Set-Request header sent every time (which shouldn't be the case, as far as I understand).
我怀疑此行为是由于CORS级别上的某些配置不一致或缺少配置所致,或者是由于为会话设置的 path
( Express.use(path,middleware)
>和 Cookie({path:'/'})
).但是,尽管尝试了不同的配置,设置和标题,但我确实无法使它正常工作.
I suspect this behavior is caused by some incoherent or missing configuration at the CORS level, or due to the path
set for Sessions (Express.use(path, middleware)
, and Cookie({path: '/'})
). However, despite many attempt with different configuration, setup and headers, I really can't make it work.
任何能启发我这种行为的人,我所缺少的都是非常受欢迎的:)
谢谢!
Anyone able to enlighten me on this behavior and what I am missing is very welcome :)
Thank you!
PS:我对非CoffeeScript开发人员表示歉意;)
PS: My apologies to the non-CoffeeScript developers ;)
推荐答案
以下是答案(简单的答案):我对会话中间件的配置错误; cookie.domain
选项引起了该问题.这是正确的配置:
Here's the answer (simple one):
I had misconfigured my Session middleware; The cookie.domain
options was causing the problem.
Here's the proper configuration :
sessionConfig: ->
secret: 'whatever'
cookie:
secure: false
httpOnly: false
快速/会话中间件不再需要/不存在此选项;不知道为什么我最初使用它,可能来自过时的参考资料(用于表达/cookie解析器或表达/cors).
This option isn't required/existing (anymore?) with the express/session middleware; Not sure why I originally used it, probably something from an outdated reference (to express/cookie-parser or express/cors).
这篇关于CORS通话后,Express Session无法持续的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!