我创建了一个社交网络,发展得很好。我想使用socket.io和node实现实时通知。
嗯。已经做到了,而且是这样。。。
用户A向用户B发送消息,然后节点服务器通过发送通知写入对用户B吼叫的通道。
每个用户在浏览网站时都会连接到自己的频道:
<script type="text/javascript">
var socket = io.connect( 'https://notificationserver.com/' );
socket.on( 'notifications_USERID', function( data ) {
var data_type=data.data_type;
//sample
if(data_type=="message"){
$.notify("You got a new message", "success");
}
});
</script>
很简单。用户的通道是notifications_USERID。
这当然不安全。如果有人将html页面保存到它的计算机上并加载它,他们就会收到特定的用户通知。
那么,只有真正的登录用户才能安全访问它,最好的方法是什么呢?
更新
我使用curl将数据发送到节点服务器,如下所示:
$curl = curl_init();
$data = json_encode(array("receiverid"=>$uid,"secret"=>"SOMESECRET"));
curl_setopt($curl, CURLOPT_URL, "http://notificationserver:1334");
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_TIMEOUT, 1);
curl_setopt($curl,CURLOPT_CONNECTTIMEOUT,1);
curl_exec($curl);
这是我的应用程序JS文件
var http = require('http'),
fs = require('fs');
var key="SOMESECRET";
var app = http.createServer(function (request, response) {
if (request.method == 'POST') {
var body = '';
var jsonString = '';
request.on('data', function (data) {
body += data;
jsonString += data;
if (body.length > 1e6) {
request.connection.destroy();
}
});
request.on('end', function () {
var json_data=JSON.parse(jsonString);
var receiverid=json_data.receiverid;
var secret=json_data.secret;
if(secret==key){
NewMessageNotify(receiverid);
}else{
request.connection.destroy();
}
});
}else{
response.writeHead(200, {'Content-Type': 'text/html'});
response.write("<h1>Hello World</h1>");
response.end();
}
}).listen(1334);
var io = require('socket.io').listen(app);
function NewMessageNotify(receiverid){
io.sockets.emit("notifications_"+receiverid,{ data_type: "message" });
}
您有一个破碎的安全模型,并将所有用户的所有消息发送给每个人(实际上是在广播它们)。只要稍微调整一下客户端javascript,或者从任何计算机运行一段流氓javascript,以比socket.io
稍低的级别连接,任何用户都可以监听所有消息。
在此代码中:
function NewMessageNotify(receiverid){
io.sockets.emit("notifications_"+receiverid,{ data_type: "message" });
}
io.sockets.emit()
部分将该消息发送到所有打开的套接字。那根本不是你想做的。您希望"Bob"的消息只发送到Bob的套接字。然后,除了向你证明自己是Bob的人之外,其他人都没有机会查看它们。
因此,要只将Bob的消息发送到Bob的套接字,您必须在Bob和他的套接字之间保持一些相关性。通常,这将作为身份验证过程的一部分来完成(您没有显示),因此,当有人连接到您的服务器并成功通过Bob身份验证时,您将记录Bob和特定套接字之间的链接。我不太了解socket.io,不知道它是否有一个内置的机制来维护这个链接,但我知道你可以用几种方法来做到这一点。
如果你不打算拥有数以亿计的用户,你可以使用聊天室功能。当Bob使用唯一的用户ID登录时,你可以用他的名字加入他的聊天室。然后,当你想给鲍勃发消息时,你只需在聊天室里播放他的名字。他将是该聊天室的唯一监听器,因为你的服务器永远不会让其他人进入。这有点扭曲了聊天室的设计目的,但由于你的userId必须是唯一的,它允许你使用用户名作为聊天室名称和套接字。io会自动为你保留名称和套接字之间的链接。
你可以创建自己的用户和socket.id的数据结构。当给定的用户连接到你的服务器并成功通过身份验证时,你只需将他们添加到你的数据结构中。当它们断开连接时,您可以将它们移除。
样本代码:
var users = {};
io.on('connection', function(socket){
// new socket connection here
// authenticate the user
// after successful login and authentication, add them to our data structure
var username = "...";
users[username] = socket;
socket.on('disconnect', function() {
// remove them from our data structure
delete users[username];
});
});
然后,向特定用户发送数据:
function NewMessageNotify(receiverid){
// get socket for that specific user
var socket = users[receiverid];
if (socket) {
socket.emit("notifications",{ data_type: "message" });
}
}