-
Notifications
You must be signed in to change notification settings - Fork 1
Authorizing
Socket.IO has support has for 2 different authorization methods. Authorization can be applied globally which will be done during the initialization / handshaking process or it can be done per namespace.
Global authorization can be used together together or independent from each
other. The only thing they have in common is the handshakeData object. The
data object is generated with the request data from the handshake. So to have a
better understanding of how to work with authorization you first need to
understand the handshaking process.
When a client wants to establish a persistent real time connection with the Socket.IO server it needs to start a handshaking processing. The handshake is initiated with either a XHR request or JSONP request (for cross domain requests).
When the server receives a connection it will start gathering data from the request that might be needed later this is done for two reasons:
- Users might want authorize the clients based on information from the headers or IP address.
- Not all transports sends headers when they attempt to establish a real time connection with the server, so we store the handshake data internally so we are sure users can re-use this data again for when the client is connect. For example you might want to read out the session id from the cookie headers and initialize the Express session for the connected socket.
The handshakeData object contains the following information:
{
, headers: req.headers // the headers that where send with this request
, time: (new Date) +'' // date time of the connection
, address: socket.address() // location and port object
, xdomain: !!headers.origin // was it a cross domain request
, secure: socket.secure // https connection?
}The address is the result of
socket.address()
After we fetched all information we check if a global authorization function has
been configured. If this is the case we pass it in authorization function the
handshakeData object and a callback function. When the callback is called, we
store the handshakeData internally so it can later be accessed during the
connection event through the socket.handshake property. Based on the
response of the callback we are going to either send a 403, 500 or a 200
success response.
#Global authorization
Global authorization is enabled by setting the authorization configuration
method.
io.configure(function (){
io.set('authorization', function (handshakeData, callback) {
callback(null, true); // error first callback style
});
});In side the authorization function above you receive 2 arguments
- handshakeData, the handshakeData object that we generated during handshaking.
- callback, as handshakes might require database look-ups. It requires 2
arguments,
errorwhich can be undefined or a String in case of the error andauthorizeda Boolean indicating if the client is authorized.
Sending an error or setting the authorized argument to false both result in not allowing the client to connect to the server.
Because the handshakeData is stored after the authorization you can
actually add or remove data from this object.
var io = require('socket.io').listen(80);
io.configure(function (){
io.set('authorization', function (handshakeData, callback) {
// findDatabyip is an async example function
findDatabyIP(handshakeData.address.address, function (err, data) {
if (err) return callback(err);
if (data.authorized) {
handshakeData.foo = 'bar';
for(var prop in data) handshakeData[prop] = data[data];
callback(null, true);
} else {
callback(null, false);
}
})
});
});You can now access stored during the connection event:
io.sockets.on('connection', function (socket) {
console.log(socket.handshake.foo == true); // writes `true`
console.log(socket.handshake.address.address); // writes 127.0.0.1
});#Namespace authorization