2013-08-27 57 views
3

我的應用程序中的會話數據使用node-client-sessions(如Using secure client-side sessions to build simple and scalable Node.JS applications中建議的)處理,現在我有socket.io(websockets)來處理一些實時功能。我想通過握手時的會話數據對登錄用戶進行身份驗證。但是socket.io在握手時給了我們這個對象,並且它不完全公開請求對象。我需要訪問請求的會話屬性。有任何想法嗎?如何訪問socket.io上的會話數據(節點客戶端會話)?

我正在使用expressjs(nodejs)。

UPDATE

啓發@ LaurentPerrin的答案,我一頭扎進客戶端的會話源,發現暴露的解碼和編碼功能。也許不如直接混淆會話對象那麼簡單,但是到目前爲止非常有效。

我的代碼,到目前爲止:

/*jslint node: true, es5: true, nomen: true, unparam: true */ 

'use strict'; 

var encode = require('client-sessions').util.encode, 
    decode = require('client-sessions').util.decode, 
    cookie = require('cookie'), 

    cookieSettings = require('./persistors/cookieSettings'), 

    authorized = { 
     '[email protected]': 1 
    }; 

module.exports = function websocket(io) { 
    io.set('authorization', function (handshakeData, callback) { 
     var session_data; 
     if (!handshakeData.headers.cookie) { 
      callback({ 
       status: 'forbidden', 
       reason: 'no session', 
       source: 'socket_io' 
      }, false); 
      return; 
     } 
     session_data = decode(cookieSettings, cookie.parse(handshakeData.headers.cookie).session).content; 
     if (authorized[session_data.email]) { 
      handshakeData.session_data = session_data; 
      callback(null, true); 
     } else { 
      // callback({ 
      //  status: 'forbidden', 
      //  reason: 'unauthorized', 
      //  source: 'socket_io' 
      // }, false); 
      callback(null, false); 
     } 
     return; 
    }); 
    io.set('transports', ['websocket', 'flashsocket']); 
    io.sockets.on('connection', function (socket) { 
     console.log('connected') 
     socket.on('credenciamento', function (data) { 
      console.log(socket.handshake.session_data.email); 
      socket.broadcast.emit('credenciamento', { 
       inscrito_id: data.inscrito_id 
      }); 
     }); 
    }); 
}; 

這是不完整。但授權部分似乎工作得很好。 =)

現在,關於回調函數。起初,我用@LaurentPerrin來傳遞一個帶有錯誤迴應的對象。但它會產生警告。 Socket.io認爲,錯誤內容時發生:

warn - handshake error [object Object]

所以在第二一刻我通過null作爲第一個參數時未授權:

info - handshake unauthorized

考慮socket.io的方式瞭解各事情,第二種方式似乎在語義上更加正確。 =)

我選擇第二種方式。自己挑一個。

+0

感謝您瞭解暴露的編碼/解碼方法!我想知道你是否有充分的客戶端會話來處理套接字?我問,因爲當在後端的套接字事件中更改會話對象時,似乎沒有更新cookie(帶有會話信息)的可能性。我可以切換到LongPolling,但會失去套接字的好處,或者我可以在會話中使用Redis後端,但會失去客戶端會話的好處。任何線索? – japrescott

+0

@japrescott我只需要授權,所以我不認爲我做的不僅僅是授權。但是,你不能修改「cookie」並重新編碼嗎?我認爲它會起作用......那麼,讓我知道!我會檢查我的代碼。這是一箇舊的項目... 無論如何,你可能仍然需要Redis,請記住: 「立即撤銷Persona會話 與服務器端會話相比,客戶端會話的主要缺點之一是服務器沒有更有能力摧毀會議。「 – slacktracer

+1

我的解決方案現在包含使用cookiesession存儲用戶ID,以便我可以在將來永遠檢測用戶。一旦使用數據庫命中'授權',用戶數據將存儲在redis中,以便稍後進行用戶信息/會話檢索。進一步的請求可以從那裏得到信任,並且不需要db命中來驗證用戶,我可以直接從redis中獲取信任並且信任其用戶調用。但是中間人攻擊矢量仍然存在,但可以用ssl關閉。 – japrescott

回答

4

不知道它是否完全一樣,但我寫在我的情況。請注意,我需要直接使用快速依賴關係來避免版本問題。

var cookie = require('express/node_modules/cookie'), 
    parseSignedCookie = require('express/node_modules/connect').utils.parseSignedCookie, 
    parseJSONCookie = require('express/node_modules/connect').utils.parseJSONCookie; 

… 

io.set('authorization', authorizeSocket); 

… 

function authorizeSocket(handshake, done) { 
    if (!handshake.headers.cookie) 
    return done({status: 'forbidden', reason: 'no session', source: 'socket_io'}, false); 

    var cookies = cookie.parse(handshake.headers.cookie), 
     signed = cookies['your_session_cookie']; 

    if (!signed) 
    return done({status: 'forbidden', reason: 'tampered cookie', source: 'socket_io'}, false); 

    var raw = parseSignedCookie(signed, 'your_session_secret'), 
    json = parseJSONCookie(raw); 

    if (!json || !json.passport || !json.passport.user) 
    return done({status: 'forbidden', reason: 'bad session', source: 'socket_io'}, false); 

    // finally... 
    var user = json.passport.user; 

    handshake.user = user; 

    done(null, true); 
} 
+0

我想一個想法。但它是否適用於客戶端會話?我的意思是,它似乎沒有揭示一種方法來解密cookie中的會話數據。這個會話對象(它很棒)可以在每個請求中訪問(並且使用socket.io時距離我的距離還有點遠)。 – slacktracer

+0

或者它也可以!你的回答是繼續前進的靈感!非常感謝你! (我仍然想訪問會話對象,它是如此接近!= P) – slacktracer

+0

最後一次,謝謝。我主要以你向我展示的方式去做。使用'client-sessions'似乎更容易。我用一些代碼和注意事項更新了我的答案。 您可能感興趣的是:傳遞一個對象作爲完成函數的第一個參數意味着在授權過程中出現錯誤。語義...是不是授權錯誤? Socket.io消息讓我覺得沒有。 – slacktracer