identifying users upon some action or disconnected

Viewed 293

I'm new to node

I have a PHP/Laravel cms and I have a simple Nodejs game server which is basically a loop generating some numbers

I connect my PHP backend to Nodejs via Socketio and use Socketio-JWT to identify the user

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

my serverside

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

as you can see I have an object called _online_users and I store authenticated users in this object and then I send it to the clients so they know who is online io.sockets.emit('update_online_users' , _online_users );

here is the problem, when the user gets disconnected

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

I have to update my _online_users object and remove disconnected user .... how should I go about this? I was thinking maybe I can store the token itself in the _online_users

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

and when the user gets disconnected I get the disconnected token from the socket and remove the user from an object by that token

of course, this is all theory! I'm not sure if that's the way to go .... first of all, I can't access the token itself from the socket !

or let's say one of the users sends another request to node server, how can I identify the user sending the request?

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

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

    })

is there anything unique insocket.decoded_token that I can use as id? if so I can store it in the online users send it back and forth when the user requests something

basically I'm lost and appreciate any pointers

2 Answers

You can use a middleware now in the newer versions of socket-io. So you can check if the user is logged in by the jwt token that is sent with the request. If decoded successfully you can assign the user info to the current socket and call next() and go to the event you are listening for. Here is the example provided in the socket-io docs slightly modified for your case.

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

You are doing well!

Since you are adding socket event handlers in the 'authenticated' handler you still have access to socket.decoded_token.userid.

This should be enough:

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

or to be a little more concise:

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

Edit: About unauthenticated socket I don't know; doc says nothing. You could try something like:

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 => {
  //...
});

Hope this helps.

Related