15

TL;DR:

Express、Express-Session、および Express-Cors を使用して、バックボーン アプリと Node.js サーバー間で実行される複数の API 呼び出しにわたるセッションの永続化を成功させることができません。呼び出しのたびにセッションが再初期化/失われたようです。

長いバージョン:

localhost:3000で実行されている Node.js サーバーで次の呼び出しを実行するクライアント Backbone/React/Flux アプリケーションを実行していlocalhost:4242ます。

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
 [...]

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はユーザーのログインであり、API トークンをセッションに保存しようとします。2 番目の呼び出しGET /api/usersは、最初の呼び出しが成功した直後にトリガーされ、ユーザー情報を取得します。

バックボーン方式

ログイン用のセッションモデルのバックボーンメソッドは次のとおりです。

  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 への呼び出し

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() メソッドをオーバーライドしているモデルとコレクションの両方で同じこと)。

そのため、Console.log(options)inBackbone.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 のセットアップとメソッド

これが私の 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'

これが私の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 リクエストが正常に実行されていることがわかるように、トークンを適切に取得し、それをセッション内に保存しようとしています。

ただし、2 番目の呼び出しではセッションが永続化されず、最初の呼び出しで実際に設定している変数 (accessToken) にアクセスできません。

ログと 2 つの呼び出しの HTTP ヘッダーを見ると、セッション ID が変更され、各要求が行われるため、毎回セッションが再初期化されているように見えます。私が理解している限りではそうです)。

この動作は、CORS レベルでの構成の一貫性がないか、欠落していることが原因であるか、またはpathセッション ( Express.use(path, middleware)、およびCookie({path: '/'})) のセットが原因であると思われます。ただし、さまざまな構成、セットアップ、およびヘッダーを何度も試みたにもかかわらず、実際には機能しません。

この振る舞いと私が欠けているものについて私を啓発できる人は誰でも大歓迎です:)
ありがとう!

PS: CoffeeScript を使用していない開発者には申し訳ありません ;)

4

1 に答える 1