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

60

我有一个使用Node.js作为后端、普通JavaScript作为前端,并利用socket.io实现的应用程序。该应用程序拥有一个登录系统,目前是客户端在连接时立即发送其登录数据。

现在我想让登录数据随着握手数据一起发送,这样我就可以在连接时直接将用户登录,或在登录数据无效时拒绝授权。

我认为最好将我的附加数据放在握手数据的头部,则有任何想法如何实现呢?(如果可能的话,不修改socket.io,但如果这是唯一的方法,我也可以接受)

7个回答

148
作为很多评论已经指出的,在 Socket.IO 的 1.0 发布中,API 已经发生了变化。现在应该通过一个中间件函数来进行身份验证,请参见“身份验证差异” @ http://socket.io/docs/migrating-from-0-9/#authentication-differences。由于旧文档似乎已经消失,我会把我的原始答案包含在下面,以供任何卡在 <1.0 版本上的人使用。

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'));
});

Pre 1.0

您可以在客户端的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()
});

3
谢谢!正是我想要的!+1 - Wingblade
2
太好了,这帮了我大忙。非常感谢您。 - Art Geigel
3
@FacundoOlano,如何以不同的方式实现此目标?无论是查询字符串、postvars还是作为特殊头部,如果没有使用https,则令牌都是可被嗅探的。但我真的很想知道您缓解此类MIM攻击的解决方案。 - japrescott
2
@japrescott,如果没有https,您不能期望任何安全性;但即使使用https,在查询字符串中发送令牌也不可取。我的解决方法是发送身份验证消息并将令牌放在消息正文中。我在这里解释了它(https://facundoolano.wordpress.com/2014/10/11/better-authentication-for-socket-io-no-query-strings/)。 - Facundo Olano
1
@AlexWright 是的,这是最新的版本,昨天安装的。 - Deminetix
显示剩余9条评论

19

这在v1.0.0中已经被更改。请参阅迁移文档

基本上,

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字段? - Harry Moreno
@HarryMoreno 使用 socket.request._query - Ciaran

10

对于 socket.io v1.2.1,请使用以下内容:

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

7

这是我用来向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 - Valter Lorran
4
这可能与版本有关。我只能通过使用socket.handshake.query.userOrWhatever来使它起作用。 - makc

1
也许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上回答了https://github.com/Automattic/socket.io/issues/2022的问题。 - Harry Moreno

1

虽然这是一个旧的线程,但假设您将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()
  }
}

我现在正在使用它来完成一个项目,它运行良好。


0

我发现一个小问题,看不到 .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
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接