在 socket.io 中与握手数据一起发送自定义数据?

Posted

技术标签:

【中文标题】在 socket.io 中与握手数据一起发送自定义数据?【英文标题】:Send custom data along with handshakeData in socket.io? 【发布时间】:2012-11-24 14:15:55 【问题描述】:

所以我有一个运行 node js 的应用程序,其中 socket.io 作为后端,普通的 javascript 作为前端。我的应用程序有一个登录系统,目前只是让客户端在连接后立即发送其登录数据。

现在我认为将登录数据与握手数据一起发送会更好,所以我可以直接让用户在连接时登录(而不是在建立连接后)分别在登录数据无效时拒绝授权.

我认为最好将我的附加数据放在握手数据的标题部分,所以有什么想法可以做到吗? (如果可能,不必修改 socket.io,但如果这是我可以忍受的唯一方式)

【问题讨论】:

【参考方案1】:

正如许多 cmets 在其1.0 版本中更改的 Socket.IO API 下面所指出的那样。现在应该通过中间件功能完成身份验证,请参阅“身份验证差异”@http://socket.io/docs/migrating-from-0-9/#authentication-differences。由于旧文档似乎已经消失,我将为停留在

1.0 及更高版本:

客户端:

//The query member of the options object is passed to the server on connection and parsed as a CGI style Querystring.
var socket = io("http://127.0.0.1:3000/",  query: "foo=bar" );

服务器端:

io.use(function(socket, next)
    console.log("Query: ", socket.handshake.query);
    // return the result of next() to accept the connection.
    if (socket.handshake.query.foo == "bar") 
        return next();
    
    // call next() with an Error if you need to reject the connection.
    next(new Error('Authentication error'));
);

前 1.0

您可以将第二个参数中的 query: param 传递给客户端的 connect(),该参数将在服务器上的授权方法中可用。

我刚刚在测试它。在我的客户端上:

var c = io.connect('http://127.0.0.1:3000/',  query: "foo=bar" );

在服务器上:

io.set('authorization', function (handshakeData, cb) 
    console.log('Auth: ', handshakeData.query);
    cb(null, true);
);

然后服务器上的输出看起来像:

:!node node_app/main.js
   info  - socket.io started
Auth:   foo: 'bar', t: '1355859917678' 

更新

3.x 及更高版本

您可以使用 auth 参数作为客户端中 connect() 的第二个参数传递身份验证负载。

客户端:

io.connect("http://127.0.0.1:3000/", 
    auth: 
      token: "AuthToken",
    ,
  ),

在服务器端你可以使用socket.handshake.auth.token访问它

服务器端:

io.use(function(socket, next)
    console.log(socket.handshake.auth.token)
    next()
);

【讨论】:

谢谢!正是我想要的! +1 优秀。这对我帮助很大。谢谢。 @FacundoOlano,如何以不同的方式实现这一目标?无论是查询字符串、postvars 还是作为特殊标头,如果不使用 https,则令牌是可嗅探的。但我真的很想知道您缓解此类 MIM 攻击的解决方案 @japrescott 你不能指望没有 https 的任何安全性;但即使使用 https,也不建议在查询字符串中发送令牌。我的解决方法是发送身份验证消息并将令牌放入消息正文中。我已经解释过了here @AlexWright 是的,这是昨天安装的最新版本【参考方案2】:

这已在 v1.0.0 中进行了更改。见migration docs

基本上,

io.set('authorization', function (handshakeData, callback) 
  // make sure the handshake data looks good
  callback(null, true); // error first, 'authorized' boolean second 
);

变成:

  io.use(function(socket, next) 
  var handshakeData = socket.request;
  // make sure the handshake data looks good as before
  // if error do this:
    // next(new Error('not authorized');
  // else just call next
  next();
);

【讨论】:

如何从服务器端的socket.request 获取query 字段? @HarryMoreno 使用socket.request._query【参考方案3】:

对于 socket.io v1.2.1 使用这个:

io.use(function (socket, next) 
  var handshake = socket.handshake;
  console.log(handshake.query);
  next();
);

【讨论】:

【参考方案4】:

这是我用于向 nodejs 和 server.io 服务器客户端发送查询数据的代码。

var socket = io.connect(window.location.origin,  query: 'loggeduser=user1' );

io.sockets.on('connection', function (socket) 
    var endp = socket.manager.handshaken[socket.id].address;
    console.log("query... " + socket.manager.handshaken[socket.id].query.user);

【讨论】:

这是最好的解决方案。但是socket.manager.handshaken[socket.id].query.user 应该是socket.manager.handshaken[socket.id].query.loggeduser 这可能与版本有关。我只能让它与 socket.handshake.query.userOrWhatever 一起使用【参考方案5】:

也许 api 已更改,但我执行以下操作以获取服务器的额外信息。

// client
io.connect('localhost:8080',  query: 'foo=bar', extra: 'extra');

// server
io.use(function(sock, next) 
  var handshakeData = sock.request;
  console.log('_query:', handshakeData._query);
  console.log('extra:', handshakeData.extra);
  next();
);

打印

_query:  foo: 'bar',
  EIO: '3',
  transport: 'polling',
  t: '1424932455409-0' 
extra: undefined

如果有人知道如何通过握手将数据从客户端发送到服务器查询参数中没有请告诉我。

更新我后来遇到了这个语法的问题

io.connect('localhost:8080?foo=bar');

是我目前正在使用的。

【讨论】:

作者回复自 slack github.com/Automattic/socket.io/issues/2022【参考方案6】:

旧线程,但假设您将 jwt 令牌/会话 ID 存储在会话 cookie(标准内容)中,默认情况下无论如何在握手时(socket.io-client)都会传递给服务器,我注意到了。 通过 cookie 获取握手的身份验证信息(通过中间件或 on.connection)有什么问题吗? 例如。

io.on('connection', function(socket) 
  // assuming base64url token
  const cookieStr = socket.handshake.headers.cookie
  const matchRes =
    cookieStr == null
      ? false
      : cookieStr.match(/my-auth-token=([a-zA-Z0-9_.-]+)/)
  if (matchRes) 
    // verify your jwt...
    if ( tokenIsGood(matchRes[1]) 
      // handle authenticated new socket
     else 
      socket.emit('AUTH_ERR_LOGOUT')
      socket.disconnect()
    
   else 
    socket.emit('AUTH_ERR_LOGOUT')
    socket.disconnect()
  

我现在正在将它用于一个项目,并且运行良好。

【讨论】:

【参考方案7】:

看到.loggeduser

发现了一个小问题
io.sockets.on('connection', function (socket) 
    var endp = socket.manager.handshaken[socket.id].address;
    console.log("query... " + socket.manager.handshaken[socket.id].query.loggeduser);
                                                                         // ↑ here

【讨论】:

以上是关于在 socket.io 中与握手数据一起发送自定义数据?的主要内容,如果未能解决你的问题,请参考以下文章

在Socket.io-client中发送自定义头。

在 node.js 中与 socket.io 私聊

socket.io 握手返回错误“传输未知”

是否可以使用 WebSocket 握手发送自定义数据?

如何在 Socket.io 中与 Heroku 服务器建立 Socket 连接?

在 Kotlin 中与 @RequestParam 一起使用时,自定义 HashMap 类获取参数类型不匹配