socket.handshake.query
atualmente permite que os dados sejam definidos em connect
, mas não podem ser atualizados por referência antes de reconnect
ser disparado. Isso causa problemas ao autorizar uma conexão de soquete com tokens de atualização.
//client
io.connect("wss://socket.server.com", {
query : {
token:"something dynamic"
}
});
Se o servidor for reiniciado e os clientes reconnect
, o token pode estar desatualizado ao reautorizar o soquete.
//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
}
});
Permitir que a consulta seja function
:
io.connect("wss://socket.server.com", {
query : function(){
return {
token:"something dynamic"
}
}
});
No construtor de Socket atual:
if (opts && opts.query) {
this.query = opts.query;
}
Pode ser alterado para este:
if(opts && opts.query) {
this.query = typeof opts.query == 'function' && opts.query.call(this) || opts.query;
}
+1
correção para o bug # 1086 também deve resolver seu problema. A alteração das opções de consulta após a conexão bem-sucedida funcionava com a versão mais antiga do socket.io-client, mas com a versão atual, a referência ao objeto de consulta foi perdida :(
@reeltimedoktor momento você deve ser capaz de atualizar o query
objeto reconnect_attempt
evento:
socket.on('reconnect_attempt', function () {
socket.io.opts.query = { token: /* ... */ };
});
A solução de @darrachequesne não parece funcionar para mim :(
Estou em socket.io-client
version 2.3.0
no cliente, com um servidor de nó com socket.io
version 2.3.0
.
No cliente, estou fazendo o seguinte:
socket.on('reconnect_attempt', async () => {
const newToken = await getNewToken();
socket.io.opts.query = {
token: latestToken,
};
});
E então o servidor está autenticando o token usando um middleware passado para io.use()
(que deve ser acionado quando o soquete estiver se conectando ou reconectando, afaik?).
No momento, a autenticação do servidor está falhando ao reconectar, dizendo que o token expirou - parece que o novo token não está sendo atribuído corretamente a socket.io.opts.query.token
- alguma ideia por quê?
Obrigado :)
Atualização: Parece que há vários lugares diferentes no objeto de soquete onde o token de autenticação está armazenado, por exemplo, socket.io.engine.query.token
, socket.io.engine.transport.query.token
. Eles não são preenchidos automaticamente quando você define socket.io.opts.query.token
. No entanto, alterá-los ainda não afeta o que os servidores 'vêem' - ele ainda vê apenas o token antigo.
O token também parece estar incluído como um parâmetro de URL em alguns dos campos de url no objeto de soquete. Talvez eles precisem ser atualizados também?
Depois de investigar mais, parece que definir o token em socket.io.opts.query.token
é suficiente para alterar o token para reautenticação na reconexão - outra coisa parece ser o problema para meu aplicativo, talvez algo a ver com a geração do token de autenticação do firebase. Portanto, para qualquer pessoa que se deparar com isso, a solução de @darrachequesne funciona!
Ok, acho que corrigi-lo - você precisa ter certeza de que está recebendo o novo token de forma síncrona no retorno de chamada 'reconnect_attempt', ou seja, não faça isso:
socket.on('reconnect_attempt', async () => {
const newToken = await getNewToken(); // won't work
socket.io.opts.query = {
token: latestToken,
};
});
Parece que a autenticação do lado do servidor estava sendo feita antes que o novo token fosse definido. Se você obtiver o token de forma síncrona (obtendo-o algum tempo antes e armazenando-o e, em seguida, apenas recuperando-o no retorno de chamada do ouvinte), o servidor obtém o novo token de autenticação a tempo da autenticação de reconexão.
com "socket.io-client": "3.0.4"
estou recebendo TS2341: Property 'opts' is private and only accessible within class 'Manager'.
erro. Estou usando "typescript": "4.1.3"
Ok, acho que corrigi-lo - você precisa ter certeza de que está recebendo o novo token _synchronously_ no retorno de chamada 'reconnect_attempt', ou seja, não faça isso:
socket.on('reconnect_attempt', async () => { const newToken = await getNewToken(); // won't work socket.io.opts.query = { token: latestToken, }; });
Parece que a autenticação do lado do servidor estava sendo feita antes que o novo token fosse definido. Se você obtiver o token de forma síncrona (obtendo-o algum tempo antes e armazenando-o e, em seguida, apenas recuperando-o no retorno de chamada do ouvinte), o servidor obtém o novo token de autenticação a tempo da autenticação de reconexão.
Estamos tendo um problema semelhante. Mas minha solução atual é disconnect
do lado do servidor quando a autenticação falhar. ao receber o evento disconnect
no cliente, reconstruímos a consulta / cabeçalho com a chamada de promessa assíncrona. No momento em que atinge o evento reconnecting
, ele já tem o novo valor na consulta / cabeçalho.
Para futuros leitores:
O comportamento da opção query
em Socket.IO v2 é um pouco estranho, pois é usado em ambos:
Portanto, não tenho certeza de como poderíamos corrigi-lo de uma forma compatível com versões anteriores ...
Observe que isso foi corrigido no Socket.IO v3, pois agora você pode usar a opção auth
:
// plain object
const socket = io({
auth: {
token: "abc"
}
});
// or with a function
const socket = io({
auth: (cb) => {
cb({
token: "abc"
});
}
});
Também deve funcionar com uma função async
:
const socket = io({
auth: async (cb) => {
cb({
token: "abc"
});
}
});
Veja também:
Comentários muito úteis
@reeltimedoktor momento você deve ser capaz de atualizar o
query
objetoreconnect_attempt
evento: