首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Socket.IO身份验证与共享会话数据,io.use()是如何工作的?

Socket.IO身份验证与共享会话数据,io.use()是如何工作的?
EN

Stack Overflow用户
提问于 2018-04-26 07:15:05
回答 2查看 0关注 0票数 0

受到如何与Socket.IO 1.x和Express 4.x共享会话的启发,我以某种“干净”的方式实现了套接字认证,无需使用cookie解析器并从头文件中读取cookie,但很少有项目对我来说仍不清楚。示例使用上一个稳定的socket.io版本1.3.6。

var express      = require('express'),
    session      = require('express-session'),
    RedisStore   = require('connect-redis')(session),
    sessionStore = new RedisStore(),
    io           = require('socket.io').listen(server);

var sessionMiddleware = session({
    store   : sessionStore,
    secret  : "blabla",
    cookie  : { ... }
});

function socketAuthentication(socket, next) {
  var sessionID = socket.request.sessionID;

  sessionStore.get(sessionID, function(err, session) {
      if(err) { return next(err); }

      if(typeof session === "undefined") {
          return next( new Error('Session cannot be found') );
      }
      console.log('Socket authenticated successfully');
      next();
  });
}

io.of('/abc').use(socketAuthentication).on('connection', function(socket) { 
  // setup events and stuff
});

io.use(function(socket, next) {
  sessionMiddleware(socket.request, socket.request.res, next);
});

app.use(sessionMiddleware);
app.get('/', function(req, res) { res.render('index'); });
server.listen(8080);

index.html

<body>
    ...
    <script src="socket.io/socket.io.js"></script>
    <script>
       var socket = io('http://localhost:8080/abc');
    </script>
</body>

所以io('http://localhost:8080/abc');从客户端发送初始HTTP握手请求到服务器,从服务器可以收集cookie和许多其他请求信息。所以服务器可以通过socket.request访问该初始请求。

我的第一个问题是为什么握手请求不在快速会话中间件的范围之内?(更普遍地在app.use中间件范围内?)在某种程度上,我预计这个app.use(sessionMiddleware); 在该初始请求之前触发,然后轻松访问socket.request.session

其次,中间件定义的场景io.use()会发生什么?仅用于初始HTTP握手请求?它似乎io.use()是用于套接字相关的东西(问题是:什么东西),而app.use标准的请求。

我不太清楚为什么在上面的例子中io.use()被解雇了io.of('/abc').use()。我故意写下这个命令,io.of('/abc').use()首先看它是否会起作用,并且工作正常。应该反过来写。

最后,socket.request.res也像一些人在链接问题中指出的,有时undefined导致应用程序崩溃,问题可以通过提供空对象而不是socket.request.res来解决

EN

回答 2

Stack Overflow用户

发布于 2018-04-26 15:39:27

尽管@oLeduc是正确的,但还有几件事要解释..

为什么握手请求不在快速会话中间件的范围内?

这里最大的原因是express中的中间件被设计为处理特定于请求的任务。不是全部,但大多数处理程序使用标准req, res, next语法。如果我能说,套接字是“无需请求”的。你拥有的事实socket.request是由于握手的方式,并且它使用HTTP。所以socket.io中的这些人首先要求进入你的套接字类,以便你可以使用它。它不是由快速团队设计的,以便与套接字和TCP一起工作。

使用io.use()定义的中间件会触发哪些场景?

io.use是表达use中间件方式的一种紧密表示。在快递中,中间件在每个请求上执行,对吧?但是套接字没有请求,并且在每个套接字上使用中间件会很尴尬,因此它们已经在每个连接上执行它。但是,除了在实际请求被处理(和响应)之前堆叠和使用快速中间件,Socket.IO使用中间件进行连接,甚至实际握手之前!如果你想使用那种非常方便的中间件(为了保护你的服务器免受垃圾邮件攻击),你可以拦截握手。更多信息可以在passport-socketio的代码中找到

为什么io.use()在io.of('/ abc')。use()之前触发?

关于这个的真正解释可以在这里找到,这是这个代码:

Server.prototype.of = function(name, fn){
    if (String(name)[0] !== '/') name = '/' + name;

    if (!this.nsps[name]) {
        debug('initializing namespace %s', name);
        var nsp = new Namespace(this, name);
        this.nsps[name] = nsp;
    }
    if (fn) this.nsps[name].on('connect', fn);
    return this.nsps[name];
};

在代码的开头,有这样一行代码:

this.sockets = this.of('/');

所以,在一开始就有一个默认的命名空间。就在那里,你可以看到它立即有一个connect听众附着在它上面。之后,每个命名空间都会得到完全相同的connect侦听器,但是因为NamespaceEventEmitter,侦听器会一个接一个地添加,所以它们会一个接一个地触发。换句话说,默认名称空间首先是侦听器,所以它首先触发。

我不认为这是故意设计的,但恰巧是这样:)

为什么socket.request.res未定义?

说实话,我对此并不确定。这是因为engine.io的实现方式 - 您可以在这里阅读更多内容。它连接到常规服务器,并发送请求以进行握手。我只能想象,有时出错时头部与响应分开,这就是为什么你不会得到任何答案。无论如何,仍然只是猜测。

希望信息有帮助。

票数 0
EN

Stack Overflow用户

发布于 2018-04-26 16:52:00

为什么握手请求不在快速会话中间件的范围内?

因为socket.io将附加到一个http.Server,它是快速下的图层。它在socket.io 的源代码中的评论中提到。

这是因为第一个请求是一个常规的http请求,用于将请求的无状态http连接升级为完全状态的websocket连接。因此,它必须通过适用于常规http请求的所有逻辑,这没什么意义。

使用io.use()定义的中间件会触发哪些场景?

每当创建一个新的套接字连接时。

所以每次客户端连接时都会调用使用io.use()注册的中间件。然而,一旦客户端连接上了,当从客户端接收到数据包时它就不会被调用。如果连接是在自定义命名空间或主命名空间上启动的,则无关紧要,它将始终被调用。

为什么io.use()在io.of('/ abc')。use()之前触发?

命名空间是socket.io实现的一个细节,事实上,websockets将始终首先命中主命名空间。

为了说明这种情况,请看这段代码和它产生的输出:

var customeNamespace = io.of('/abc');

customeNamespace.use(function(socket, next){
  console.log('Use -> /abc');

  return next();
});

io.of('/abc').on('connection', function (socket) {
  console.log('Connected to namespace!')
});

io.use(function(socket, next){
  console.log('Use -> /');

  return next();
});

io.on('connection', function (socket) {
  console.log('Connected to namespace!')
});

输出:

Use -> /
Main namespace
Use -> /abc
Connected to namespace!

查看socket.io团队添加到他们的文档中的警告:

重要说明:命名空间是Socket.IO协议的实现细节,并且与底层传输的实际URL无关,默认为/socket.io/...。

为什么socket.request.res未定义?

据我所知,它永远不应该是未定义的。这可能与您的具体实施有关。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/-100008269

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档