2013-10-09 4 views
1

Я пытаюсь сохранить все подключенные к клиенту объекты. Но, как я понял, все подключенные клиенты имеют одинаковые идентификаторы. Поэтому, если у объекта connections есть все подключенные сокеты, когда я пытаюсь отправить сообщение на connections['mac'], он просто появляется на моем экране как отправленный мной мне. Вот код аутентификации:Socket.io присваивает одинаковый идентификатор всем клиентам

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

Я это Auth код в маршрутах файл раньше, и я полагаю, что я должен быть запущен в этом от app.js. Я сделал это, и он все еще не работает, как я этого хочу. Может ли кто-нибудь сказать мне, что мне не хватает?

+0

Где находится c ode, где вы отправляете сообщение одному из подключений? – Gaurav

+0

обновил вопрос кодом обмена – amit

+0

Можете ли вы уменьшить это до одного файла node.js и html-файла, который демонстрирует проблему? Я думаю, что в настоящее время слишком много недостающих частей, чтобы полностью ответить на этот вопрос. Это может быть связано с регенерацией сеанса, но это очень сложно сказать. –

ответ

4

Проблема с вашим кодом в том, что у вас есть обработчик входящего соединения Socket.IO внутри одного из ваших HTTP-маршрутов. Это означает, что обработчик применяется только после доступа к маршруту, кроме того, что у вас должен быть только один обработчик соединения 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 
}); 

Теперь, когда объект сеанса и печенье анализатор доступны, мы можем определить параметры авторизации:

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' ('Страница не авторизована.', False);'. – hexacyanide

+0

в порядке. я должен это сделать. Я внедрил изменения, которые вы предложили выше, и я получаю сообщение об ошибке «отладка - авторизованный/предупреждающий» или «Ошибка сеанса связи». на консоли. есть идеи? – amit

1

У вас есть io.sockets.on('connection'... внутри одного пользователя. Поэтому каждый раз, когда пользователь входит в систему, будет добавлен еще один прослушиватель.

Так что, может выглядеть следующим образом (кто-то входит в систему, то они подключаются к разъему)

журналы Пользователь1 в пользователя 1 подключается к гнезду (псевдо, как он сам)

пользователя 2 входит в пользователя 2 подключается к разъему (псевдо, как пользователь 1, то, как псевдо-User 2)

пользователь 3 бревен в пользователе 3 подключается к разъему (псевдо как 1, 2, а затем 3

Если пользователь 1 обновляет страницу, он будет псевдо как 1, 2, 3, а также

Проблема прослушивает все больше и больше каждый раз, когда кто-то входит в.

Вы должны слушать подключить внешнюю функцию, происходит несколько раз.

я обычно делаю что-то вроде следующего

на английском: пользователь загружает на страницу, он подключается к разъему И.О., то он делает АЯКС $ .get поэтому сервер может использовать свою сессию, чтобы дать ему токен, который разрешит его сокет. Затем он отправляет токен, и сервер знает, что сокет разрешен.

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) 
    }); 
}); 

, очевидно, это очень медленно, что является той же причиной, почему многие люди не экономят сокеты в таком глобальном месте. Попытайтесь сделать то, что вы пытаетесь сделать с большим количеством обратных вызовов, и переосмыслите проблему с нуля. Или оставьте это как взломать, пока не получите больше трафика, и это станет проблемой производительности. :)

Смежные вопросы