我正在开发一款小型多人游戏。我想介绍身份验证。我正在使用Node.js和Socket.io。
当用户到达主页面时 - 我希望他们加入游戏,无论他们是否已登录 - 但他们将无法在其中执行任何操作(仅限观看)。
我怎样才能在已经打开的套接字上验证用户?
如果他们离开网站并回来后我可以保持身份验证吗?你能通过网络套接字传递cookie吗?
修改
进一步提出我的问题。我有一个可能的想法是提供websocket连接,然后当他们尝试登录时,它将用户名和密码作为消息传递给websocket。
client.on('onLogin', loginfunction);
然后,我可以获取用户名和密码,检查数据库,然后获取套接字的会话ID并将其传递到某个地方,说该会话已经过该用户的身份验证。
这样安全吗?我还能在套接字上实现一个cookie,以便它们可以回来吗?在socket.io中是否有任何方法表明套接字现在已经过身份验证而不是手动检查收到的每条消息?
干杯
答案 0 :(得分:6)
这实际上并不太难,但你正以错误的方式接近它。几件事:
你不能用socket.io 设置一个cookie;但是,您可以随时获取任何连接客户端的cookie值。为了设置cookie,你必须发送一个新的http响应,这意味着用户必须首先发送一个新的http请求(也就是刷新或转到一个新的页面,这听起来不可能在这里)。 / p>
是:socket.io是安全的(在任何传输数据的范围内)。
因此,您可以执行以下操作:
在用户的初始连接上,创建一个具有唯一会话ID的cookie,例如从Express的会话中间件生成的cookie。您需要配置这些不会在会话结束时到期(否则它会在关闭浏览器后立即过期)。
接下来,您应该创建一个对象来存储Cookie会话ID。每次设置新的connect.sid cookie时,都会在新对象中存储默认值false(表示用户已通过会话进行身份验证,但未通过登录进行身份验证)
在用户登录时,将套接字发送到服务器,然后您可以在其中验证登录凭据,然后更新您创建的会话ID对象,以读取当前套接字ID的真实(登录)。
现在,当收到新的http请求时,请阅读cookie.sid,并检查其对象中的值是否为真。
它应该类似于以下内容:
var express = require('express'),
http = require('http'),
cookie = require('cookie');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);
app.use(express.cookieParser());
app.use(express.session({
secret: 'secret_pw',
store: sessionStore,
cookie: {
secure: true,
expires: new Date(Date.now() + 60 * 1000), //setting cookie to not expire on session end
maxAge: 60 * 1000,
key: 'connect.sid'
}
}));
var sessionobj = {}; //This is important; it will contain your connect.sid IDs.
//io.set('authorization'...etc. here to authorize socket connection and ensure legitimacy
app.get("/*", function(req, res, next){
if(sessionobj[req.cookies['connect.sid']]){
if(sessionobj[req.cookies['connect.sid']].login == true){
//Authenticated AND Logged in
}
else{
//authenticated but not logged in
}
}
else{
//not authenticated
}
});
io.sockets.on('connection', function(socket){
sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid'].login = false;
sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid'].socketid = socket.id;
socket.on('login', function(data){
//DB Call, where you authenticate login
//on callback (if login is successful):
sessionobj[cookie.parse(socket.handshake.headers.cookie)['connect.sid']] = true;
});
socket.on('disconnect', function(data){
//any cleanup actions you may want
});
});
答案 1 :(得分:2)
但首先,免责声明:我为Realtime.co工作,而不是尝试做任何类型的广告。我与开发人员密切合作,我只是想通过为您的问题提供开箱即用的解决方案来帮助您。此外,作为一名游戏玩家,我无法避免试图帮助人们将游戏带到那里!
Realtime使用身份验证/授权层,您可以在其中为频道提供用户读/写权限。当用户进入网站时,您可以向他们授予对游戏频道的只读权限,一旦他们登录,您就可以授予他们写入权限。这可以通过执行身份验证并重新连接到服务器(它可以在客户端完成)轻松完成。不过,我会在服务器端进行,以提高安全性。
Realtime有一个Node.js API,因此您可以轻松地将其与您的服务器集成。由于它还具有许多其他平台(包括移动设备)的API,并且它们都以相同的方式工作,因此您可以让您的游戏在同一通信层上的多个平台上工作,同时完全控制通道。
感谢阅读。
编辑:
您可以在此处阅读文档以获取更多信息:http://docs.xrtml.org/
答案 2 :(得分:0)
Socket.io可以选择传递extraHeaders。可以使用它来传递来自客户端的令牌。服务器将使用所需的身份验证算法来解密令牌并获得user_id
。
socket.js
import io from 'socket.io-client';
export const socket = io('https://remote-url');
export const socketAuth = () => {
socket.io.disconnect(); //This uses the same socket and disconnect with the server.
socket.io.opts.extraHeaders = {
'x-auth-token': JSON.parse(window.localStorage.getItem('auth-token')),
};
socket.io.opts.transportOptions = {
polling: {
extraHeaders: {
'x-auth-token': JSON.parse(window.localStorage.getItem('auth-token')),
},
},
};
socket.io.open(); //Opens up a new connection with `x-auth-token` in headers
};
client.js
import { socket, socketAuth } from 'utils/socket';
socket.on('unauthenticated-messages', () => {
someAction();
});
//After user logs in successfully
socketAuth();
socket.on('authenticated-messages', () => {
someAction();
});