【问题标题】:socket.io authentication after socket established建立套接字后的socket.io身份验证
【发布时间】:2012-02-04 00:08:58
【问题描述】:

我正在开发一款小型多人游戏。我想介绍身份验证。我正在使用 Node.js 和 Socket.io。

当用户到达主页时——无论他们是否登录,我都希望他们加入游戏——但他们将无法在其中做任何事情(只能观看)。

然后我该如何在已经打开的套接字上对用户进行身份验证?

如果他们离开网站然后回来,我还能保持身份验证吗?可以通过网络套接字传递 cookie 吗?

编辑

进一步我的问题。我的一个可能想法是提供 websocket 连接,然后当他们尝试登录时,它将用户名和密码作为消息传递给 websocket。

client.on('onLogin', loginfunction);

然后我可以获取用户名和密码,检查数据库,然后获取套接字的会话 ID 并将其传递给某个地方,以说明会话已通过该用户的身份验证。

这安全吗?我还能在套接字上实现一个 cookie 以便他们可以回来吗? socket.io 中是否有任何方法可以说明套接字现在已通过身份验证,而不是手动检查收到的每条消息?

干杯

【问题讨论】:

  • 请参阅this article,了解如何验证 socket.io 会话。
  • 是的,我实际上已经阅读了那篇文章。虽然我很高兴设置一个 cookie,但如果套接字已经打开,它不允许在同一页面上登录。如果用户禁用了 cookie,它也会受到影响?
  • 在建立连接并完成握手后,是否有办法将连接设置为在 socket.io 中进行了身份验证?用户可以在准备好连接现有连接时提供登录详细信息,服务器可以验证并返回唯一的会话 ID。客户端 javascript 然后可以保存一个 cookie 以供将来使用。
  • 您希望能够在同一页面上重新登录用户吗? 99.99% 的用户启用了 cookie。如果有的话,他们更有可能禁用 Javascript。

标签: authentication node.js websocket socket.io


【解决方案1】:

这实际上并不太难,但是您以错误的方式接近它。几件事:

  1. 你不能设置一个带有socket.io的cookie;但是,您可以随时获取任何已连接客户端的 cookie 值。为了设置 cookie,你必须发送一个新的 http 响应,这意味着用户必须首先发送一个新的 http 请求(也就是刷新或转到一个新页面,这听起来对你来说是不可能的)。

  2. 是的:socket.io 是安全的(在任何传输数据都可以的范围内)。

因此,您可以执行以下操作:

在用户的初始连接上,创建一个具有唯一会话 ID 的 cookie,例如从 Express 的会话中间件生成的那些。不过,您需要将它们配置为不会在会话结束时过期(否则它们会在关闭浏览器后立即过期)。

接下来,您应该创建一个对象来存储 cookie 会话 ID。每次设置新的 connect.sid cookie 时,将默认值 false 存储在新对象中(意味着用户已通过会话进行身份验证,但未通过登录)

在用户登录时,向服务器发送一个套接字发射,然后您可以在服务器上验证登录凭据,然后更新您创建的会话 id 对象以读取当前套接字 id 的 true(登录)。

现在,当接收到一个新的 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
    });

});

【讨论】:

  • 如果我错了请纠正我,但通常不会认为永不过期的会话不安全
  • @Mozoby 我的代码将 cookie 设置为在经过一定时间后过期 - 这不是无限期的。我这样做是因为最初的问题似乎表明返回用户仍应登录,这意味着我不能像默认情况下那样让 cookie 在浏览器关闭时过期。
【解决方案2】:

克里斯,我无法回答,因为我不是 socket.io 方面的专家,但我也许可以尝试为您指出另一个可以帮助您的方向 - 并节省一些开发时间。

但首先,免责声明:我在 Realtime.co 工作,并不想做任何类型的广告。我与开发人员密切合作,我只是想通过为您的问题提供开箱即用的解决方案来帮助您。另外,作为一名游戏玩家,我不能不努力帮助人们将他们的游戏推向市场!

Realtime 使用身份验证/授权层,您可以在其中向用户提供对通道的读/写权限。当用户进入网站时,您可以授予他们对游戏频道的只读权限,一旦他们登录,您就可以授予他们写入权限。这可以通过进行身份验证发布并重新连接到服务器来轻松完成(这都可以在客户端完成)。不过,为了提高安全性,我会在服务器端进行。

Realtime 有一个 Node.js API,因此您可以轻松地将它与您的服务器集成。由于它还具有适用于许多其他平台(包括移动平台)的 API,并且它们都以相同的方式工作,因此您实际上可以让您的游戏在同一个通信层上的多个平台上运行,同时完全控制渠道。

感谢阅读。

编辑:

您可以在此处阅读文档以获取更多信息:http://docs.xrtml.org/

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 2012-10-30
      • 1970-01-01
      • 2021-02-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-29
      • 2014-04-21
      • 1970-01-01
      • 2015-10-30
      相关资源
      最近更新 更多