我正在尝试保存对象中客户端中的所有连接。但正如我所知,连接的客户端都具有相同的ID。因此,如果对象connections
具有所有已连接的套接字,当我尝试向connections['mac']
发送消息时,它就会显示在我发送给我的屏幕上。这是授权码:
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 :(得分:4)
您的代码存在的问题是您的一条HTTP路由中有一个Socket.IO传入连接处理程序。这意味着只有在访问路由之后才应用处理程序,除了你应该只有一个Socket.IO连接处理程序。
您需要做的是分离HTTP和Socket.IO处理程序,并且由于您正在使用会话,因此允许Socket.IO处理授权。
首先,将您的套接字处理程序移到HTTP处理程序之外:
app.post('/', handler);
io.sockets.on('connection', handler);
然后,定义Socket.IO授权设置以从Express获取会话对象。假设您使用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;
});
});
答案 1 :(得分:1)
您在单个用户登录中有io.sockets.on('connection'...
。因此,每次用户登录时,都会添加另一个侦听器。
所以它可能看起来像这样(某人登录,然后他们连接到套接字)
User1登录 用户1连接到套接字(伪自己)
用户2登录 用户2连接到套接字(伪作为用户1,然后伪作为用户2)
用户3登录 用户3连接到套接字(伪为1,2,然后3
如果用户1刷新页面,他将伪为1,2,3,以及
每次有人登录时,问题就越来越多。
您需要在多次发生的函数之外侦听连接。
我通常做类似以下的事情
英文:用户加载一个页面,他连接到socket io,然后他做一个ajax $ .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)
});
});
显然这很慢,这就是为什么没有很多人将套接字保存到这样的全球地方的原因。尝试使用更多回调来尝试做什么,并从头开始重新思考问题。或者将它留作黑客,直到你获得更多流量,这成为一个性能问题。 :)