前段时间我偶然发现了同样的问题。这是我的解决方案(稍作修改 - 用于生产)。
我们将使用 Socket.IO namespaces 为每个用户创建私人 房间。然后我们可以将消息(服务器端)发送到特定的房间。在我们的例子中 - 只有特定的用户才能收到它们。
但是要为每个连接的用户创建私人房间,我们必须首先验证他们的身份。我们将为此使用简单的身份验证中间件,supported by Socket.IO since its 1.0 release。
1。认证中间件
自 1.0 版本以来,Socket.IO supports middleware. 我们将使用它:
- 验证连接用户身份,使用JSON Web Token(见
jwt-simple)他发送给我们作为查询参数。 (请注意,这只是一个示例,还有很多其他方法可以做到这一点。)
- 将他的用户 ID(从令牌中读取)保存在
socket.io 连接实例中,以供以后使用(在第 2 步中)。
服务器端代码示例:
var io = socketio.listen(server); // initialize the listener
io.use(function(socket, next) {
var handshake = socket.request;
var decoded;
try {
decoded = jwt.decode(handshake.query().accessToken, tokenSecret);
} catch (err) {
console.error(err);
next(new Error('Invalid token!'));
}
if (decoded) {
// everything went fine - save userId as property of given connection instance
socket.userId = decoded.userId; // save user id we just got from the token, to be used later
next();
} else {
// invalid token - terminate the connection
next(new Error('Invalid token!'));
}
});
这里是关于如何在客户端初始化连接时提供令牌的示例:
socket = io("http://stackoverflow.com/", {
query: 'accessToken=' + accessToken
});
2。命名空间
Socket.io namespaces 让我们能够为每个连接的用户创建私人房间。然后我们可以将消息发送到特定的房间(因此只有其中的用户才能接收它们,而不是每个连接的客户端)。
在上一步中,我们确保:
- 只有经过身份验证的用户才能连接到我们的 Socket.IO 接口。
- 对于每个连接的客户端,我们将用户 ID 保存为
socket.io 连接实例 (socket.userId) 的属性。
剩下要做的就是在每次连接时加入适当的房间,名称等于新连接客户端的用户 ID。
io.on('connection', function(socket){
socket.join(socket.userId); // "userId" saved during authentication
// ...
});
现在,我们可以发出只有该用户会收到的有针对性的消息:
io.in(req.user._id).emit('article.created', data); // we can safely drop req.user._id from event name itself