socket.io room authorisation - node.js

I have a use case of socket.io where, within an individual namespace, a client can connect to several rooms. A user needs to authenticate on a per-room basis (because they may not be allowed to access those data streams).
Obviously I can check the authorisation on connection to the namespace using a middleware function and some auth data, but unless those rooms are already in socket.rooms when the connection is initiated, I do not know how to check, when a socket joins a room, whether or not it is authorised and subsequently force it to leave the room if it is not authorised.
Is there a join event or equivalent way of doing this? Like the connection event for a namespace but for a room.
EDIT
Having read through the source for socket.io, it appears that no events are triggered when a socket joins a room, but I might have misunderstood something: on reading the source of socket.io-client, joining rooms isn't inherent in the system, suggesting that this is only something that can be triggered on the server side. In that case, I'm assuming I have to manage the client's joining of rooms myself? If this is true, then I can just have something like:
socket.on('join', function(data) { ... });
so that when a socket wants to listen to a particular data stream, it just emits a "join" event, with some data on which room it wants to join, and I handle the whole thing on the server?

Joining a room can only be done on the server. The client typically sends an application-specific message to the server that indicates to your app that they want to join a specific room and then the server carries out that operation on the user's behalf if the request is valid.
So, all you have to do is route all your code on the server that could join a room through one particular function that can do whatever authentication you want to do. For example, you could simply create a function that was the only way your server code would ever put a socket into a room:
function joinAuth(socket, room) {
// can do anything you want here before actually joining the room
}

Related

How to avoid users see data from other user socket?

I have a dasboard that is making socket request every five seconds, sometimes, some users start getting data from other user socket request, but at the begging everything is working fine.
I have tried with sticky-session, diferrent socket instance, personalized socket event names.
if someone unsderstand my problem and i have a solution, i would be grateful.
Sockets are, by definition, separate from each other. I suspect the issue is that you're emitting to a namespace rather than to a particular socket.
io.of('someNamespace').emit('data');
vs
io.of('someNamespace').on('connection', (socket) => {
socket.emit('data');
});
In the first example we're sending data to all sockets in the namespace. In the second we're only sending data to a particular socket. The difference is in where you're emitting the data.

Socket io creates rooms when a socket connects

Every time a socket joins a room is created in my application. Is this normal behavior?
I am not creating these rooms, as you can tell the room name is called the ID of the socket, which I find weird. Is this normal behavior?
This is normal behavior. Socket.io creates a room with the name of the connection's socket.id and automatically places only that socket in the room. This allows you to do things like:
io.to(someSocketId).emit(...)
because the socket.id is also a room name. Since socket.id values are unique and random and because all room participation is controlled by the server only, it's really just a server housekeeping thing that doesn't affect anything else.
If you have some reason to want to be able to discern which rooms are ones you created and which ones are the automatic socket.id form, you can put a unique prefix on the ones that you create such as an underscore and then you can tell which ones are yours and which ones are created by the system.
When the connection disconnects, that room will also go away.

Practical or Best socket.io implementation

i have a problem over implementing sockets. Case:
the user has n number of rooms in his list,
user should be able to receive notifications from each of the rooms.
method 1) open a socket for each room user has. in this user has to open multiple sockets for each room
method 2) users opens a single socket with room name = userid,
node maintains a list ('room_user') of each room and users in that room (this can be done on connection).
eg
room_user:{
room1 : {
user1Id, user2Id
}
room2 : {
user1Id, user3Id
}
}
For sending a message the server gets the userid's from the list for a specified room and then emits the message in a loop to all users. In this approach the user has to open only one socket but the server has to emit the same message in a loop
i want to know which method would be better suited
If you consider the underlaying TCP/IP broadcast system, you would probably find that it is better that the user have a single websocket connection and the server loop and send the same message again and again (method 2 in your question).
Allow me to explain:
TCP/IP doesn't support broadcasting. For this reason, sending the same message to multiple connections is actually implemented by looping over the list of connections and sending the same message again and again...
It's true that your code will be moving the loop to a higher level of the application, but it would probably be better than having many connections that would hinder your ability to scale the application.

How to send real time notification to single user using node.js and PHP

I am trying to integrate real time notifications with Node and socket.io in a Symfony Application. I have read a lot of information about this topic and have a working Node application.
nodeClient.js
var socket = io.connect( 'http://192.168.15.106:8080' );
$('a.sendSmile').click(function(){
socket.emit( 'message', { name: 'something' } );
});
socket.on('message', function(data){
console.log(data.name);
});
The problem now is with the above which is working perfectly I am able to send real time notification to all the users at once. But what's the best way to target a single user?
For example a user can send a smile to another user so only the second user should receive the notification and not all the users.
Should I make multiple listeners for node? or any other method to do this?
You need some way of identifying which socket that connected to your server is the one you want to send data to and then you can send to just that socket. You can keep track of user names when users connect or if you have some auth system, you can keep track of which socket belongs to which authenticated user.
Your server holds a list of connected sockets. Each connected one at a time and triggered a connection event on your server when they connected. Your application needs to create a way of knowing which of those connected sockets you want to send the data to. This is not something you've described anything about how you want that to work so we can't really help more specifically.
You can dispatch a notification to single user if you can discriminate that user. For example you can get a user_id on client connection to your nodejs server (the user_id is send from client, inside message) and save it in a key-value store (like Redis, memcache, ...). In this way you can correctly dispatch the notification, arrived from the server (like Symfony2 application), to right user.
I suggest you use Redis, both as a key-value store and for its implementation pattern of the publish/subscribe usable as a channel of communication between the server and the application of realtime.

Two instances of one socket.io connection

In our app, every time a user signs in a new connection in socket.io is created. So if a user signs in simultaneously on more devices, they behave as separate connections. Instead of creating a new connection every time, I'd like to check whether the user is already connected to socket.io and if he is, I'd like to connect him to already established connection. How can this be done?
From the socket.io perspective, those ARE two connections. But if it was my app, I would do something like this:
add a user identifier (userid, username, something you identify users by) to both the users' socket.io connection (so, each time you send a message to the client, you also pass this id)
pass this id also to the client-side code on init.
So now the socket on the server side has its' socket.io id, but also your user id. Anyway, to proceed:
send this user-id to the client in it's javascript files.
on the client-side code, make a small adjustment to socket.io handler - for each received message (say, broadcast), you can now check if it's your current user-id and instead of saying 'User #351 says Hi' you can say 'You said Hi on another device' or something like that.
Of course, I'm not socket.io expert, there's could already exist a framework or lib addressing this.

Resources