2013-10-09 62 views
1

我試圖保存客戶端中的所有連接對象。但正如我所想,連接的客戶端都具有相同的ID。因此,如果對象connections具有所有連接的套接字,當我嘗試發送消息至connections['mac']時,它只會顯示在我發送給我的屏幕上。下面是身份驗證碼:Socket.io爲所有客戶端分配相同的ID

app.post('/auth', function(req, res){ // routes.auth(hash, db, io, pseudoArray, connections) 
    var username = req.body.username, 
     password = req.body.password; 
    if (username != "" && password != ""){ 
     authenticate(username, password, db, hash, function(err, user){ 
      if (user) { 
       // Regenerate session when signing in 
       // to prevent fixation 
       console.log('user authenticated'); 
       req.session.regenerate(function(){ 
        req.session.user = user.name; 
        req.session.success = 'Authenticated as ' + user.name 
        + ' click to <a href="/logout">logout</a>. ' 
        + ' You may now access <a href="/restricted">/restricted</a>.'; 

        io.sockets.on('connection', function (socket) { 
         socket.set('pseudo', req.session.user, function(){ 
          pseudoArray.push(req.session.user); 
          var sessionuser = req.session.user; 
          socket.emit('pseudoStatus', 'ok'); 
          connections[req.session.user] = socket; 
          console.log("user " + req.session.user + " connected"); 
         }); 
        }); 
        res.cookie('rememberme', '1', { maxAge: 900000, httpOnly: true }); 
        res.redirect('home'); 
       }); 
      } else { 
       console.log('auth failed'); 
       req.session.error = 'Authentication failed, please check your ' 
        + ' username and password.' 
        + ' (use "tj" and "foobar")'; 
       res.redirect('login'); 
      } 
     }); 
    } else { 
     res.redirect('connect'); 
    } 
}); 

,我將消息發送給其他客戶端的代碼:

exports.addfriend = function(connections, io){ 
    return function(req, res){ 
     // var collection = db.get('go1'); 
     var username = req.session.user; 
     var friend = req.body.name; 
     console.log(connections[''+friend+'']); 
     connections[''+friend+''].emit('addRequest', username); 
     return; 
    } 
} 

我曾在路由,該授權碼早期版本的文件,我想我應該運行這一關app.js.我做到了這一點,它仍然沒有工作,因爲我想要它。有人能告訴我我錯過了什麼嗎?

+0

c在哪裏發送消息到其中一個連接? – Gaurav

+0

用消息代碼更新了問題 – amit

+0

您可以將此問題簡化爲顯示問題的單個node.js文件和html文件嗎?我認爲現在有太多的缺失部分要完全回答這個問題。這可能與會話更新有關,但很難說。 –

回答

4

您的代碼的問題是,您有一個HTTP路由內的Socket.IO傳入連接處理程序。這意味着處理程序只在訪問路由後才應用,除了應該只有一個Socket.IO連接處理程序。

您需要做的是將HTTP和Socket.IO處理程序分開,並且由於您使用的是會話,因此允許Socket.IO處理授權。

首先,將你的插座處理程序HTTP處理程序之外:

app.post('/', handler); 
io.sockets.on('connection', handler); 

然後,定義Socket.IO授權設置來從快遞會話對象。假設你正在使用express.cookieParser()因爲你有會話,會話店,我們需要從外部參考他們:

var MemoryStore = express.session.MemoryStore; 

var session_key = 'express.sid'; 
var session_secret = 'for signed cookies'; 
var session_store = new MemoryStore(); 

var cookieParser = express.cookieParser(session_secret); 

app.use(cookieParser); 
app.use(express.session({ 
    secret: session_secret, 
    store: session_store, 
    key: session_key 
}); 

現在,會話對象和cookie的解析器都可以訪問,我們可以定義的權限設置:

io.set('authorization', function(handshake, callback) { 
    if (handshake.headers.cookie) { 
    cookieParser(handshake, null, function(err) { 
     // Use depends on whether you have signed cookies 
     // handshake.sessionID = handshake.cookies[session_key]; 
     handshake.sessionID = handshake.signedCookies[session_key]; 

     session_store.get(handshake.sessionID, function(err, session) { 
     if (err || !session) { 
      callback('Error or no session.', false); 
     } else { 
      handshake.session = session; 
      callback(null, true); 
     } 
     }); 
    }); 
    } else { 
    callback('No session cookie found.', false); 
    } 
}); 

此代碼的功能是檢查客戶端是否有會話cookie。否則,它不授權Socket.IO連接。如果是這樣,它會解析cookie,找到相關的會話,並將會話存儲在套接字中。現在,您可以通過套接字訪問會話屬性:

app.post('/', function(req, res) { 
    req.session.user = 'genericusername'; 
    res.send(200); 
}); 

io.sockets.on('connection', function(socket) { 
    var session = socket.handshake.session; 
    session.user // genericusername 
}); 

至於你的代碼,它會再看看這樣的:

var http = require('http'); 
var express = require('express'); 
var app = express(); 

var server = http.createServer(app); 
var io = require('socket.io').listen(server); 

var MemoryStore = express.session.MemoryStore; 

var session_key = 'express.sid'; 
var session_secret = 'for signed cookies'; 
var session_store = new MemoryStore(); 

var cookieParser = express.cookieParser(session_secret); 

app.use(cookieParser); 
app.use(express.session({ 
    secret: session_secret, 
    store: session_store, 
    key: session_key 
}); 

的路由處理:

app.post('/auth', function(req, res) { 
    var username = req.body.username, 
    var password = req.body.password; 

    if (username != '' && password != '') { 
    authenticate(username, password, db, hash, function(err, user) { 
     if (user) { 
     req.session.regenerate(function() { 
      req.session.user = user.name; 
      req.session.success = 'Authenticated as ' + user.name + ' click to <a href="/logout">logout</a>. You may now access <a href="/restricted">/restricted</a>.'; 
      res.cookie('rememberme', '1', { 
      maxAge: 900000, 
      httpOnly: true 
      }); 
      res.redirect('/home'); 
     }); 
     } else { 
     req.session.error = 'Authentication failed, please check your username and password. (use "tj" and "foobar")'; 
     res.redirect('/login'); 
     } 
    }); 
    } else { 
    res.redirect('/connect'); 
    } 
}); 

然後是Socket.IO配置:

io.set('authorization', function(handshake, callback) { 
    if (handshake.headers.cookie) { 
    cookieParser(handshake, null, function(err) { 
     // Use depends on whether you have signed cookies 
     // handshake.sessionID = handshake.cookies[session_key]; 
     handshake.sessionID = handshake.signedCookies[session_key]; 

     session_store.get(handshake.sessionID, function(err, session) { 
     if (err || !session) { 
      callback('Error or no session.', false); 
     } else { 
      handshake.session = session; 
      callback(null, true); 
     } 
     }); 
    }); 
    } else { 
    callback('No session cookie found.', false); 
    } 
}); 

io.sockets.on('connection', function(socket) { 
    var session = socket.handshake.sessionl 
    socket.set('pseudo', session.user, function() { 
    socket.emit('pseudoStatus', 'ok'); 
    connections[session.user] = socket; 
    }); 
}); 
+0

精彩。謝謝。我現在正在嘗試這個。我想知道的一件事是:我不希望套接字在所有頁面上都處於活動狀態。只是實際的聊天頁面。怎麼做? – amit

+0

您可以在授權過程中檢查'handshake.url'。一個簡單的'if(handshake.url!='/ page')回調('Page not authorized。',false);'。 – hexacyanide

+0

好吧。我必須這樣做。我已經實現了上面提出的更改,並且正在收到「調試授權/警告 - 握手錯誤錯誤或沒有會話」。在控制檯。有任何想法嗎? – amit

1

您在單個用戶登錄中有一個io.sockets.on('connection'...。所以每次用戶登錄時,都會添加另一個偵聽器。

因此,它可能是這樣的(有人登錄,然後他們連接到插座)

User1登錄時 用戶1連接到插座(僞作爲他自己)

用戶2個日誌中 用戶2連接到插座(僞爲用戶1,然後僞如用戶2)

用戶3個在日誌用戶 3連接到插座(僞爲1,2,然後是3

如果用戶1刷新頁面,他會在你需要聽的功能外連接僞爲1,2,3,以及

的問題是聽越來越多,每次有人在登錄。

那發生多次。

我通常做類似如下

英語

:用戶加載了一個網頁,他連接到插座的IO,然後他做了AJAX的$不用彷徨,這樣服務器可以使用其會話給他令牌,將授權他的套接字。然後他發送令牌,並且服務器知道該套接字已被授權。

app.get('/socket_token', function(req, res, next){ 
    var socket_token = Math.random();/* probably want to use crypto here instead*/ 
    mysql.query('update users set users.socket_token = ? where users.id = ?', [ socket_token, req.session.userId], function(err, result){ 
    if(result) 
     res.json({userId: req.session.userId, socket_token: socket_token}); 
    else 
     res.send('DOH!'); 
    }); 
}); 

global.all_my_sockets = [] 

io.sockets.on('connnection', function(socket){ 

    socket.emit('hey_you_are_connected'); 

    socket.on('authorize', function(credentials, callback){ 
    if(credentials.userId) 
     mysql.query('select * from users where id = ?', [credentials.userId], function(err, user){ 
     if(user.socket_token == credentials.socket_token){ 
      socket.set('authorized', true); 
      socket.set('userId', user.id); 

      // This is probably bad since what if he has 2 browser windows open? 
      all_my_sockets[user.id] = socket 

      callback('that socket token is authorized'); 
     } else { 
     //handle it 
     callback('that socket token is no good'); 
     } 
     }) 

    }); 
    socket.on('disconnect', function(){ 
    socket.get('userId', function(id){ 
     if(id) 
     delete all_my_sockets[id]; 
    }); 
    }); 
}) 

,並在客戶端

socket = io.connect(); 
socket.on('hey_you_are_connected', function(){ 
    $.get('/socket_token', function(credentials){ 
    socket.emit('authorize_token', credentials, function(res){ 
     console.log(res); // did we authorize socket? 
    }); 
    }); 
}); 

我輸入這個把我的頭頂部,有可能是一個錯誤,但它應該是非常接近你想要做什麼。

因此,在all_my_sockets [id]中保存套接字時會遇到一些問題,即每個用戶只能有1個套接字,並且如果他們有多個瀏覽器打開呢?

您應該嘗試以不同的方式構建代碼,因此您不需要全局套接字,否則,只需將它們推送到陣列,以便每個用戶都可以存在多個套接字。

all_my_sockets.push(socket); 
... 
socket.on('disconnect', function(){ 
    if(all_my_sockets.indexOf(socket) != -1) 
    all_my_sockets.splice(all_my_sockets.indexOf(socket), 1) 
}) 

,如果你每一個插座被推到陣列中,他們被授權之前,則實際找到插座,然後,你就必須要經過的每個:

_.each(all_my_sockets, function(socket){ 
    socket.get('userId', function(userId) { 
    if(userId) 
     doSomething(socket) 
    else 
     doSomethingUnAuthorized(socket) 
    }); 
}); 

顯然這是非常緩慢的,這就是爲什麼沒有很多人將套接字保存到像這樣的全球性地方的原因。試着用更多的回調來做你想做的事情,並從頭開始重新思考問題。或者將其作爲黑客入侵,直到您獲得更多流量,併成爲性能問題。 :)