【问题标题】:Authentication in Socket.ioSocket.io 中的身份验证
【发布时间】:2015-08-29 03:04:51
【问题描述】:

我将尝试验证 socket.io 上的连接。

目前,用户首先通过 REST API 进行身份验证,然后,我向用户发送 JsonWebToken 以及经过身份验证的用户的用户名。在我打开客户端和服务器之间的连接后,我的计划是暂时从连接的套接字列表中删除该套接字,以防止在我执行身份验证时在服务器之间接收和发送数据。

在此身份验证中,我验证令牌,如果令牌有效,我将套接字的 ID 重新添加到连接的套接字列表中。唯一的问题是第一部分不起作用。我似乎无法从列表中删除套接字。

为了测试这一点,我做了以下操作。

io.on('connection', function(socket){
    //temp delete socket
    delete io.sockets.connected[socket.id];
    console.log(io.sockets.connected);
    socket.emit("test");
});

如您所见,我删除了套接字并发出一个测试事件以查看套接字是否仍然打开。客户端收到了不应该收到的消息。

有人知道为什么会这样吗?

【问题讨论】:

  • 如果套接字仍然打开。然后它总是在监听。在此之前你应该确认所有连接都已关闭。如果其中任何一个未关闭,则实时客户端将收听。谢谢。
  • 您不想暂时断开套接字。 socket.io 有一个您可以插入的身份验证方案,这样如果套接字没有进行身份验证,就永远不会接受它。请记住,所有 webSocket 连接都以 http 请求开始,因此如果您已经通过 http 进行了身份验证,您也可以将其用于 webSocket。同样从io.sockets.connected 中删除套接字不会断开套接字。
  • 我使用 rest api 对用户进行身份验证,以便他们可以使用该服务。据我所知,我可以对用户进行身份验证,但无法以相同的方式对 socket.io 会话进行身份验证。我的想法是使用令牌来确保使用套接字的人是经过身份验证的人
  • this article 的例子。如果你在其余 api 被认证的时候设置了一个 cookie,那么你可以在 socket.io 中间件中访问那个 cookie 来确定是否通过了认证。或者,您可以从 socket.io 中间件启动一个单独的身份验证进程。 socket.io 内置了访问 http cookie 或执行您自己的身份验证的功能,因此您在执行身份验证时不必断开连接,您可以将身份验证作为连接过程的一部分。
  • 让我创建一个示例,如何使用与 http 服务器相同的令牌来验证套接字客户端。

标签: node.js sockets socket.io


【解决方案1】:

socket.io 还将套接字保存在命名空间中(如果未指定,则为默认值),您需要将其删除以停止接收消息。

请参阅 this post 了解您正在尝试执行的操作的分步说明,并参阅 this module 抽象整个过程。

【讨论】:

    【解决方案2】:

    尝试使用套接字对象的断开方法,如下所示:

    io.on('connection', function(socket){
        //temp delete socket
        socket.disconnect();
    
        console.log(io.sockets.connected);
        socket.emit("test");
    });
    

    更新:

    例如,如果您的 HTTP 服务器给客户端一个令牌:

    app.post('/api/users', function (req, res) {
      var user = {
        username: req.body.username
      };
    
      var token = jwt.sign(user, secret, {expiresInMinutes: 30});
    
      res.json({token: token});
    });
    

    然后您可以重复使用该令牌来验证您的 websocket 连接。

    来自客户端的令牌发送代码(html文件)将是:

    socket = io.connect('http://localhost:4000', {
      query: 'token=' + validToken,
      forceNew: true
    });
    

    服务器(socketio)中的socketio授权码为:

    // here is being used a socketio middleware to validate
    // the token that has been sent
    // and if the token is valid, then the io.on(connection, ..) statement below is executed
    // thus the socket is connected to the websocket server.
    io.use(require('socketio-jwt').authorize({
      secret: secret,
      handshake: true
    }));
    
    
    
    // but if the token is not valid, an error is triggered to the client
    // the socket won't be connected to the websocket server.
    io.on('connection', function (socket) {
      console.log('socket connected');
    });
    

    请注意,在 express 上用于生成令牌的秘密,在 socketio 中间件的验证令牌上也使用了相同的令牌。

    我创建了一个示例,您可以在其中看到这种验证是如何工作的,源代码在这里:https://gist.github.com/wilsonbalderrama/a2fa66b4d2b6eca05a5d

    将它们复制到一个文件夹中并使用 node 运行 server.js,然后通过以下 URL 从浏览器访问 html 文件:http://localhost:4000

    但首先安装模块:socket.io、express、socketio-jwt、jsonwebtoken

    【讨论】:

    • 身份验证完成后如何重新连接?会不会像 socket.reconnect() 一样简单?
    • 认证前无需断开连接。 socket.io 有认证中间件。一个人可以直接插入它,并且套接字在经过身份验证之前不会首先连接。
    • @WilsonB​​alderrama 我确实尝试过这个,但我无法通过这个 iOS 框架让它工作。 github.com/socketio/socket.io-client-swift。问题是我每次都会收到没有发送标头的错误。
    • @AlexCatchpole 我对 iOS 没有任何经验,但您是否使用此 method 进行连接?我认为应该是 "connectParams": [ "token": userToken ]
    • @WilsonB​​alderrama 感谢您的帮助,非常感谢。
    猜你喜欢
    • 1970-01-01
    • 2019-05-23
    • 1970-01-01
    • 2018-08-03
    • 2012-11-06
    • 2016-03-24
    • 2021-11-18
    • 2013-11-02
    • 2014-12-01
    相关资源
    最近更新 更多