简体   繁体   English

CORS通话后,Express Session无法持续存在

[英]Express Session not persisting after CORS calls

TL;DR: TL; DR:

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. 无法成功在Backbone应用程序和具有Express,Express-Session和Express-Cors的Node.js服务器之间执行的多个API调用之间持久保存会话。 Looks like session is reinitialized/lost after every call. 每次通话后会话似乎都重新初始化/丢失了。

Long version: 长版:

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

Http calls Http调用

POST http://localhost:4242/api/session 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 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
 [...]

Basically the first call POST /api/session is logging-in the user and attempting to store an API token in the session. 基本上,第一次调用POST /api/session是登录用户并尝试在会话中存储API令牌。 Second call GET /api/users is triggered right after the first one succeed, and retrieving user information. 第一个调用GET /api/users在第一个调用成功之后立即触发,并检索用户信息。

Backbone method 骨干法

Here's my Backbone method on the Session model for logging-in : 这是我在Session模型上进行登录的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)

And the call to /api/users in my UserStore 以及对我的UserStore中的/ api / users的调用

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

Using those different options (I've overridden Backbone.sync in Backbone.Collection/Backbone.Model): 使用这些不同的选项(我在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)

(Simplified version: same thing for both Models and Collection, using BaseCollection and BaseModel, where I am overridding the sync() method). (简化版:使用BaseCollection和BaseModel对Models和Collection都使用相同的方法,在这里我覆盖了sync()方法)。

So that Console.log(options) in Backbone.sync(method, model, options) is returning : 因此Backbone.sync(method, model, options)中的Console.log(options) Backbone.sync(method, model, 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 setup and methods Node.js设置和方法

Here's my Node.js router setting-up Express : 这是我的Node.js路由器设置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'

Here's my Node.js method handling POST /api/session 这是我的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()

And the one handling GET /api/users 和一个处理GET /api/users

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

Node.js Log Node.js日志

Here's the log: 这是日志:

  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
---------------------------------------------

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. 如您所见,CORS请求正在正常执行,我正在正确获取令牌,然后尝试将其存储在会话中。

However in the second call the session isn't persisted and I can't access the variable (accessToken) that I am actually setting in my first call. 但是,在第二个呼叫中,会话不会保留,并且我无法访问我在第一个呼叫中实际设置的变量(accessToken)。

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). 查看两个调用的日志和HTTP标头,看起来每次会话都被重新初始化,因为会话ID不断变化,每个请求都有-并且每次发送一个Set-Request标头(这不应该据我了解,确实如此)。

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: '/'}) ). 我怀疑此行为是由于CORS级别上的某些配置不一致或缺少配置所致,或者是由于为会话设置的pathExpress.use(path, middleware)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: My apologies to the non-CoffeeScript developers ;) PS:我对非CoffeeScript开发人员表示歉意;)

Here's the answer (simple one): I had misconfigured my Session middleware; 答案是一个(简单的答案):我错误地配置了会话中间件。 The cookie.domain options was causing the problem. cookie.domain选项导致了问题。 Here's the proper configuration : 这是正确的配置:

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

This option isn't required/existing (anymore?) with the express/session middleware; express / session中间件不再需要/不存在此选项; Not sure why I originally used it, probably something from an outdated reference (to express/cookie-parser or express/cors). 不知道为什么我最初使用它,可能来自过时的参考资料(表达/ cookie解析器或表达/心律)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM