【问题标题】:identifying users upon some action or disconnected在某些操作或断开连接时识别用户
【发布时间】:2020-10-02 10:20:11
【问题描述】:

我是节点新手

我有一个 PHP/Laravel cms,我有一个简单的 Nodejs 游戏服务器,它基本上是一个生成一些数字的循环

我通过 Socketio 将我的 PHP 后端连接到 Nodejs 并使用Socketio-JWT 来识别用户

我的客户端(php/laravel)

PHP

$userToken = JWTAuth::customClaims(['userid' => Auth::user()->id, 'name' => Auth::user()->name, 'avatar' => asset_url('image/avatar-default.png')])->fromUser(Auth::user() );

html/js

        var socket = io.connect("http://localhost:666");

        socket.on('connect', function () {
            socket.emit('authenticate', {token: '{{$userToken}}'});
        });
        socket.on('authenticated', function () {
            console.log('Authenticated');
        });
        socket.on('unauthorized', function (data) {
            console.log('Unauthorized, error msg: ' + data.message);
        });

我的服务器端

const _online_users = { };
io.sockets

    .on('connection', socketioJwt.authorize({
        secret:  JWT_SECRET,
        timeout: 15000
    }))

    .on('authenticated', function(socket) {

        _online_users[socket.decoded_token.userid] = {
            name : socket.decoded_token.name ,
            avatar : socket.decoded_token.avatar ,
        }

        io.sockets.emit('update_online_users' ,  _online_users  );
            socket.on('disconnect', function() {
                 console.log(`----- @@disconnect -----`)
            });
    })  ;

如您所见,我有一个名为 _online_users 的对象,我将经过身份验证的用户存储在该对象中,然后将其发送给客户端,以便他们知道谁在线 io.sockets.emit('update_online_users' , _online_users );

这就是问题所在,当用户断开连接时

            socket.on('disconnect', function() {
                 console.log(`----- @@disconnect -----`)
            });

我必须更新我的_online_users 对象并删除断开连接的用户....我应该怎么做?我在想也许我可以将令牌本身存储在_online_users

        _online_users[socket.decoded_token.userid] = {
           token  : socket.token ,
            name : socket.decoded_token.name ,
            avatar : socket.decoded_token.avatar ,
        }

当用户断开连接时,我从套接字中获取断开连接的令牌,并通过该令牌将用户从对象中删除

当然,这都是理论!我不确定这是否是要走的路....首先,我无法从套接字访问令牌本身!

或者假设一个用户向节点服务器发送另一个请求,我如何识别发送请求的用户?

    .on('authenticated', function(socket) {

            socket.on('somaction', function() {
                 console.log(` who is this guy ? `)
            });

    })

socket.decoded_token 有什么独特的东西可以用作 id 吗?如果是这样,我可以将其存储在用户请求某些内容时来回发送的在线用户中

基本上我迷路了,感谢任何指点

【问题讨论】:

  • 我的英语不好,无法帮你,但我的广告系统中也有同样的套路。就我而言,我在redis服务器上使用了一个集合,但我不会立即断开用户连接,我会对其进行操作并在一段时间内多次发送socket.emit,如果它没有响应我的平。 redis 服务器成员的集合,并与它们在另一个集合中的连接数据一起被删除。
  • 您能对我的回答提供一些反馈吗?

标签: javascript node.js socket.io jwt jwt-auth


【解决方案1】:

您现在可以在socket-io 的较新版本中使用中间件。因此,您可以检查用户是否通过随请求发送的jwt 令牌登录。如果解码成功,您可以将用户信息分配给当前套接字并调用next() 并转到您正在侦听的事件。这是 socket-io 文档中提供的示例,针对您的情况稍作修改。

io.use(function(socket, next) {
  const handshakeData = socket.request;
  // make sure the handshake data looks good as before
  // if error do this:
    // next(new Error('not authorized'));

  // else decode jwt token here and append the user to the socket.request
  // and call next
  // pseudo code here
  const {
         authorization
       } = handshakeData.header
  let token;

  if (authorization && authorization.split(" ")[0] === "Bearer") {
        token = authorization.split(" ")[1]
    }
  let user = jwt.decode(token, secret);
  socket.request.user = user;
  next();
});

【讨论】:

    【解决方案2】:

    你做得很好!

    由于您在'authenticated' 处理程序中添加socket 事件处理程序,您仍然可以访问socket.decoded_token.userid

    这就够了:

    const _online_users = {};
    io.sockets
    
        .on('connection', socketioJwt.authorize({
            secret:  JWT_SECRET,
            timeout: 15000
        }))
    
        .on('authenticated', function(socket) {
    
            _online_users[socket.decoded_token.userid] = {
                name:   socket.decoded_token.name,
                avatar: socket.decoded_token.avatar,
            };
    
            io.sockets.emit('update_online_users', _online_users);
    
            socket.on('disconnect', function() {
                console.log(`----- @@disconnect -----`);
    
                delete _online_users[socket.decoded_token.userid];
    
                io.sockets.emit('update_online_users', _online_users);
            });
        });
    

    或者更简洁一点:

    const _online_users = {};
    io.sockets
    
        .on('connection', socketioJwt.authorize({
            secret:  JWT_SECRET,
            timeout: 15000
        }))
    
        .on('authenticated', function(socket) {
            const { avatar, name, userid } = socket.decoded_token;
    
            _online_users[userid] = { name, avatar };
            io.sockets.emit('update_online_users', _online_users);
    
            socket.on('disconnect', function() {
                delete _online_users[userid];
                io.sockets.emit('update_online_users', _online_users);
            });
    
            socket.on('any other event...', function() {
                // ... still have access to userid
            });
        });
    

    编辑:关于未经身份验证的套接字我不知道;医生什么也没说。您可以尝试以下方法:

    io.socket.on('connection', socket => {
      socket.emit('update_online_users', _online_users);
    
      // I'm afraid this closes the socket if unauthorized, you could check by yourself
      socketioJwt.authorize({
        secret:  JWT_SECRET,
        timeout: 15000
      })(socket);
    }).on('authenticated', socket => {
      //...
    });
    

    希望这会有所帮助。

    【讨论】:

    • thanx ,是的,它的工作原理如此简单,我应该看到这个 :)) .... 我也只是尝试中间件解决方案,看看它是如何工作的
    • 当然,出于学习目的,这是个好主意,但我的建议是不要添加实际上不需要的代码。
    • 知道如何向未经授权的用户发送数据吗?我的意思是他们也应该获得在线用户,但由于我使用socketioJwt.authorize 作为连接事件回调,我只能访问经过身份验证的用户套接字
    猜你喜欢
    • 1970-01-01
    • 2012-06-21
    • 1970-01-01
    • 2019-09-20
    • 1970-01-01
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多