Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/33.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js 在Express应用程序中验证Socket.IO客户端_Node.js_Authentication_Socket.io_Passport.js - Fatal编程技术网

Node.js 在Express应用程序中验证Socket.IO客户端

Node.js 在Express应用程序中验证Socket.IO客户端,node.js,authentication,socket.io,passport.js,Node.js,Authentication,Socket.io,Passport.js,我已经启动并运行了一个Express应用程序,它使用Passport.js(使用MongoDB后端)进行身份验证 一切都很顺利,但现在我面临另一个挑战: 我希望在我的项目中有某种“聊天”功能,为此我使用Socket.IO(实时传递消息) 该页面验证用户在加载之前是否已登录,但仍然可以绕过该页面 我希望Socket.IO流也得到保护和授权 如何将Socket.IO聊天系统集成到基于Passport.js的身份验证中?我不确定Passport是如何工作的,但假设它在客户端上使用会话id设置cooki

我已经启动并运行了一个Express应用程序,它使用Passport.js(使用MongoDB后端)进行身份验证

一切都很顺利,但现在我面临另一个挑战:

我希望在我的项目中有某种“聊天”功能,为此我使用Socket.IO(实时传递消息)

该页面验证用户在加载之前是否已登录,但仍然可以绕过该页面

我希望Socket.IO流也得到保护和授权


如何将Socket.IO聊天系统集成到基于Passport.js的身份验证中?

我不确定Passport是如何工作的,但假设它在客户端上使用会话id设置cookie,那么以下解决方案应该可以工作。这似乎有点骇人,但我还没有看到一个更优雅的解决方案

var connect = require('express/node_modules/connect'),
    parseSignedCookie = connect.utils.parseSignedCookie,
    Cookie = require('express/node_modules/cookie'),
    store = YOUR_SESSION_STORE_INSTANCE, // i.e. redis-store, memory, or whatever 
    sessionKey = "YOUR SESSION KEY", // defaults to connect.sid
    sessionSecret = "YOUR SESSION SECRET";

var verifyCookie = function(data, callback){
    try{
        var cookie = Cookie.parse(data.headers.cookie);
        var sessionID = parseSignedCookie(cookie[sessionKey], sessionSecret);
        store.get(sessionID, callback);
    }catch(e){
        callback(e);
    }
};

// set up socket.io to validate cookies on an authorization request
// this assumes you've assigned your socket.io server to the io variable
io.configure(function(){
    io.set("authorization", function(handshake, accept){
        if(handshake.headers.cookie){
            verifyCookie(handshake, function(error, session){
                if(error || !session)
                    accept("Invalid authentication", false);
                else
                    accept(null, true);
            });
        }else{
            accept("Invalid authentication", false);
        }        
    });
});
我这里不是100%确定,但是如果这不能正确地拾取会话,您可能必须将上面使用的会话存储更改为passport的会话存储,而不是默认的express存储或您正在使用的任何存储

希望有帮助。如果这是可行的,或者如果你找到了正确的解决方案,请发布你的发现,因为我们将来可能也会使用passport,知道如何修补我们现有的代码会很好

编辑:在进行更多的探索之后,看起来在您从cookie中获取会话数据(如上所示)之后,您必须找到用户id属性并将该数据传递给passport。他们在上展示的示例是:

编辑2:另一个选择是完全回避这个问题。在实现上面列出的解决方案之前,我们走了一条不同的路线,涉及存储在redis中的一次性令牌。在高层次上,流程是这样工作的:

  • 客户端首先通过常规HTTP请求从服务器请求令牌(实现为uuid)。这将通过express的中间件路由请求,并提供对所有会话数据的轻松访问
  • 生成令牌后,它将作为密钥-值对存储在redis中,其中令牌是密钥,会话数据是值
  • 然后将令牌传递回用户,socket.io客户端在发出初始连接“升级”请求时将该令牌作为GET参数附加到url
  • 当socket.io接收到授权请求而不是验证cookie时,它会解析url,弹出令牌作为GET参数,并尝试在redis中查询令牌所键入的键值对。如果redis查询失败或返回空数据,则拒绝授权请求。如果redis请求成功,那么您可以完全访问所有会话数据,现在您可以删除redis中的键值对 这里一个可能的问题是,您需要强制socket.io客户端在每次连接尝试时强制建立新连接。否则,它将尝试使用相同的连接,从而使用相同的令牌。如果在验证令牌一次后删除它们,这将阻止套接字重新连接。根据您的应用程序,这可能是所需的行为。这是为了我们的,所以我们保持原样,但这仍然是值得知道的


    这种方法还使WS-authentication机制独立于WS-library。出于安全原因,Sockjs不提供连接请求时对cookie的访问,因此这种方法使我们从socket.io切换到Sockjs更容易。

    如果您正在开发基于Express 4.x版和socket.io 1.x版的应用程序,您可能需要阅读本文:

    在我的例子中,验证过程的代码如下所示:

    io.use(function(socket, next) {
        var handshake = socket.handshake;
    
        if (handshake.headers.cookie) {
            var req = {
                headers: {
                    cookie: handshake.headers.cookie,
                }
            }
    
            cookieParser(config.session.secret)(req, null, function(err) {
                if (err) {
                    return next(err);
                }
                var sessionID = req.signedCookies[config.session.name] ||
                                req.cookies[config.session.name];
    
                var sessionStore = new MongoStore({ db: global.db});
                sessionStore.get(sessionID, function (err, session) {
                    if (err) {
                        return next(err);
                    }
    
                    // userData bellow is written once the Express session is created
                    if (session && session.userData) { 
                        next();
                    } else {
                        return next(new Error('Invalid Session'));
                    }
                })
            });
        } else {
            next(new Error('Missing Cookies'));
        }
    });
    
    io.use(function(socket, next) {
        var handshake = socket.handshake;
    
        if (handshake.headers.cookie) {
            var req = {
                headers: {
                    cookie: handshake.headers.cookie,
                }
            }
    
            cookieParser(config.session.secret)(req, null, function(err) {
                if (err) {
                    return next(err);
                }
                var sessionID = req.signedCookies[config.session.name] ||
                                req.cookies[config.session.name];
    
                var sessionStore = new MongoStore({ db: global.db});
                sessionStore.get(sessionID, function (err, session) {
                    if (err) {
                        return next(err);
                    }
    
                    // userData bellow is written once the Express session is created
                    if (session && session.userData) { 
                        next();
                    } else {
                        return next(new Error('Invalid Session'));
                    }
                })
            });
        } else {
            next(new Error('Missing Cookies'));
        }
    });