socket.handshake.query
当前允许在connect
上设置数据,但在触发reconnect
之前不能通过引用更新。 这会在使用刷新令牌授权套接字连接时出现问题。
//client
io.connect("wss://socket.server.com", {
query : {
token:"something dynamic"
}
});
如果服务器重新启动并且客户端reconnect
,则在重新授权套接字时令牌可能已过时。
//server
io.use(function(socket, next) {
var query = socket.handshake.query;
if(isValidToken(query.token)){
next();//will never fire if the token has been updated
}
});
允许查询为function
:
io.connect("wss://socket.server.com", {
query : function(){
return {
token:"something dynamic"
}
}
});
在当前的 Socket 构造函数中:
if (opts && opts.query) {
this.query = opts.query;
}
可以改成这样:
if(opts && opts.query) {
this.query = typeof opts.query == 'function' && opts.query.call(this) || opts.query;
}
+1
修复错误 #1086 也应该可以解决您的问题。 成功连接后更改查询选项适用于较旧的 socket.io-client 版本,但在当前版本中,对查询对象的引用丢失了:(
@reeltimedoktor目前您应该能够在reconnect_attempt
事件上更新query
对象:
socket.on('reconnect_attempt', function () {
socket.io.opts.query = { token: /* ... */ };
});
@darrachequesne的解决方案似乎对我不起作用:(
我在客户端的socket.io-client
版本2.3.0
上,使用socket.io
版本2.3.0
的节点服务器。
在客户端我这样做:
socket.on('reconnect_attempt', async () => {
const newToken = await getNewToken();
socket.io.opts.query = {
token: latestToken,
};
});
然后服务器使用传递给io.use()
的中间件对令牌进行身份验证(当套接字连接或重新连接时应该触发,afaik?)。
目前服务器身份验证无法重新连接,说令牌已过期 - 似乎新令牌没有正确分配给socket.io.opts.query.token
- 任何想法为什么?
谢谢 :)
更新:似乎在存储身份验证令牌的套接字对象中有很多不同的地方,例如socket.io.engine.query.token
, socket.io.engine.transport.query.token
。 当您设置socket.io.opts.query.token
时,这些不会自动填充。 但是,更改这些仍然不会影响服务器“看到”的内容——它仍然只能看到旧令牌。
该令牌似乎也作为 URL 参数包含在套接字对象的某些 url 字段中。 也许这些也需要更新?
进一步调查后,似乎设置令牌上的socket.io.opts.query.token
足以改变令牌进行再认证的重新连接-别的东西似乎是我的应用程序的问题,也许是与火力的身份验证令牌生成。 因此,对于遇到此问题的任何其他人, @darrachequesne的解决方案有效!
好的,我想我已经修复了它 - 您需要确保在“reconnect_attempt”回调中同步获取新令牌,即不要这样做:
socket.on('reconnect_attempt', async () => {
const newToken = await getNewToken(); // won't work
socket.io.opts.query = {
token: latestToken,
};
});
似乎在设置新令牌之前已完成服务器端身份验证。 如果您同步获取令牌(通过提前获取并存储它,然后在侦听器回调中检索它),服务器会及时获取新的身份验证令牌以进行重新连接身份验证。
使用"socket.io-client": "3.0.4"
我收到TS2341: Property 'opts' is private and only accessible within class 'Manager'.
错误。 我正在使用"typescript": "4.1.3"
好的,我想我已经修复了它 - 您需要确保在“reconnect_attempt”回调中_同步_获取新令牌,即不要这样做:
socket.on('reconnect_attempt', async () => { const newToken = await getNewToken(); // won't work socket.io.opts.query = { token: latestToken, }; });
似乎在设置新令牌之前已完成服务器端身份验证。 如果您同步获取令牌(通过提前获取并存储它,然后在侦听器回调中检索它),服务器会及时获取新的身份验证令牌以进行重新连接身份验证。
我们有一个类似的问题。 但是我目前的解决方法是在身份验证失败时从服务器端转到disconnect
。 在客户端收到disconnect
事件后,我们使用异步承诺调用重新构造查询/标头。 当它到达reconnecting
事件时,它已经在查询/标题中具有新值。
对于未来的读者:
该行为query
在Socket.IO V2选择是有点不可思议,因为它是在这两个使用:
所以我不确定我们如何以向后兼容的方式修复它......
请注意,这是在 Socket.IO v3 中修复的,因为您现在可以使用auth
选项:
// plain object
const socket = io({
auth: {
token: "abc"
}
});
// or with a function
const socket = io({
auth: (cb) => {
cb({
token: "abc"
});
}
});
它也应该与async
函数一起使用:
const socket = io({
auth: async (cb) => {
cb({
token: "abc"
});
}
});
也可以看看:
最有用的评论
@reeltimedoktor目前您应该能够在
reconnect_attempt
事件上更新query
对象: