I\'m trying to create a private messaging system using socket.io
In order to associate the users with their sockets, most sites are suggesting something like this:
You're missing the most important part... Your code has to verify the usr is who he says he is. Plain and simple. I've done this multiple ways:
If users are logging in via PHP code, I move the session data to a mysql database. I then use a string on the PHP side to generate a response for a challenge to the client, who sends it to my web socket server. The WS server will challenge the client and look up the session information in the mysqldb. Done.
In my more recent developments, the actual login process is done via the web socket server. I verify the user credentials via whatever DB (in my instance, MySQL) and tie the username to the socket. Finished...
Do not purely rely on the javascript-based site to say "My name is." Otherwise, as you said, user impersonation becomes a walk in the park. You MUST validate that the user is who he says he is IF you're implementing a system where that matters. "Web sockets" themselves are not magical components that do this for you.
var people
will be accessible on the same process.
When you want to scale with multiple socket server and balancing between them, then this idea for keeping people object locally will be not helpful.
Create authenticate
event for authentication and set socket.userId
and socket.isAuthenticate = true
flag. In other events if socket.isAuthenticate is false, kick them out.
Make use of 'socket.io-redis' adpater for communication among many socket.io server. ( So when user1 from server1 send message to user2 which is in server2, will work ).
For socket - user association with multiple process, you can join Room with their userId, on authentication, join room like socket.join('myuserId');
and when to send message to that user, you can use io.to('myuserId').emit('message', "Hi How are you?"):
you can Send additional data on socket connection like this:
client side :
var c = io.connect('http://localhost:3000/', { query: "userId=value01" });
server side :
// extract userId param from connected url
io.on('connection', function(socket) {
var socket_param_userId = socket.handshake['query']['userId'];
console.log(socket_param_userId); //show value01
});
I would use jsonwebtoken
and socketio-jwt
modules for solving this security issue.
Server:
var secret = 'shhhhhh';
app.get('/getJWT', function(req, res) {
/* Do your authentication here using header and get the userId */
var userId = 'someId';
var jwt = require('jsonwebtoken');
var token = jwt.sign({ 'userId': userId }, secret);
res.json({
token: token
});
});
var socketioJwt = require('socketio-jwt');
io.use(socketioJwt.authorize({
secret: secret,
handshake: true
}));
io.sockets.on('connection', function (socket) {
var userId = socket.decoded_token.userId;
/* your logic */
Client:
var token = "token you got from the /getJWT"
var c = io.connect('http://localhost:3000/', { query: "token=" + token });
As the token is encoded with a secret, client cannot change and send it.
Refer this article to know why this is better.