NodeJS and Socket.io: Authentication across multiple modules

时间:2015-07-28 23:36:17

标签: node.js sockets authentication

I've recently picked up NodeJS again after an extensive break of a couple of years. Last time around I never really understood the proper way of including modules (dependencies) and now that I'm trying to integrate authentication I'm really stuck. That is to say, the code below is working fine, but I can't shake the feeling that I'm making it a lot harder then it should be.

This question might be borderline off-topic, but I'm looking for an answer containing guidelines and/or a clear example of best practice for organizing NodeJS code. Ideally of course, using my example of authenticating sockets.

Relevant part of app.js. Runs first.

var core = require('./core/core')();
app.set('orangeCore', core);

Core.js contains my "main" method and mainly does async API calls to other services. The idea is to submit responses from these services onto my (socket) channel as they tick in.

function core() {

    var self = this;
    init();

    self.getOrangeDevices = getOrangeDevices;
    self.bindSocket = bindSocket;

    return self;

    function init() {...
    }

    function bindSocket(socket) {
        socket.on('hello', function (msg) {
            console.log('ello! ' + msg);
        })

        socket.emit('important-stuff', {
            importantData: fromSomewhereElseInsideCore
        });
    }
}

module.exports = core;

Then there is the module for handling JWT authentication. I've based this on the socketio-jwt middleware. What I don't really like and what's causing me trouble (I do leave a lot of room here for me misunderstanding) is the auth method being done async. Since the authenticated socket doesn't get "exposed" before auth is complete, I don't understand how to bind to it in a good way. Thus I used a promise ...

var io;
var socketioJwt;
var Promise = require('bluebird');

function setup(server, app) {
    return new Promise(function (resolve, reject) {
        io = require('socket.io')(server);
        socketioJwt = require("socketio-jwt");

        io.on('connection', socketioJwt.authorize({
            secret: app.get('superSecret'),
            timeout: 15000
        })).on('authenticated', function (socket) {
            console.log('client authenticated');
            resolve(socket);
        });
    });
}

module.exports = {
    listen: function (server, app) {
        return setup(server, app);
    }
}

Finally, the www.js file which kicks of the server.

var server = http.createServer(app);
// Sockets.io
var io = require('../socket/socket-channels');
io.listen(server, app).then(function(authSocket){
    require('../core/core')().bindSocket(authSocket);
}, function(err){
    console.error(err);
});

I'm really uncertain if this is a viable approach. I'm also wondering how it will look further down the road once the app grows. Nor can I see a good way to implement the namespace feature of sockets without having to setup JWT for that as well.

1 个答案:

答案 0 :(得分:0)

虽然您的目标客户端平台不清楚, 也许你可以从这个小型lib中受益,它允许通过WebSocket连接的两方使用promises进行通信。

并且在该层外部进行身份验证。 我不知道它是否适合你实际使用它,但也许它可以给你一些灵感。

这是github上的the lib

这是一个小例子:

服务器:

C:\Users\{user}\.dnx\packages

客户端:

var io = require('socket.io')(server);
var Hook = require('./Hook');

var hook = new Hook();

var validatedSockets = {};

io.on('connection', function (socket) {
    // listen for messages
    hook.attach(socket);

    // avoid memory leak and security holes
    socket.on('disconnect', function () {
        delete validatedSockets[socket.id]
    })
});

hook.onHello(function (message, socket) {
    var token = message && message.token;

    return loadClient(token)
            .then(function (clientData) {
                if (!clientData) {
                    throw {error: "You don't have access"}
                }

                // mark socket as validated
                validatedSockets[socket.id] = clientData;

                return {ok: 1}
            })
});

hook.onHook(function (event, message, socket) {
    if (!validatedSockets[socket.id]) {
        throw {error: "You are not validated"}
    }

    // this will be added as an extra argument for every event
    return validatedSockets[socket.id];
});


hook.on('myEvent', function (message, socket, clientData) {
    // do something and return something/Promise
});

(作者就是我自己)