Socket.io-client: Permitir que socket.handshake.query seja uma função

Criado em 22 mai. 2017  ·  9Comentários  ·  Fonte: socketio/socket.io-client

Você quer:

  • [x] relatar um bug
  • [] solicitar um recurso

Comportamento atual

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.

Etapas para reproduzir (se o comportamento atual for um bug)

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

Comportamento esperado

Permitir que a consulta seja function :

io.connect("wss://socket.server.com", {
   query : function(){
      return {
         token:"something dynamic"
      }
   }
});

Configurar

  • versão socket.io: 2.0.1

Como consertar

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

Comentários muito úteis

@reeltimedoktor momento você deve ser capaz de atualizar o query objeto reconnect_attempt evento:

socket.on('reconnect_attempt', function () {
  socket.io.opts.query = { token: /* ... */ };
});

Todos 9 comentários

+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"
image

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:

  • os parâmetros de consulta (para a instância do gerenciador)
  • o handshake Socket.IO (mas apenas para um namespace não padrão)

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:

Esta página foi útil?
0 / 5 - 0 avaliações