Socket.io-client: socket.handshake.queryを関数にする

作成日 2017年05月22日  ·  9コメント  ·  ソース: socketio/socket.io-client

あなたはしたい:

  • [x]バグを報告する
  • []機能をリクエストする

現在の動作

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.ioバージョン:2.0.1

直し方

現在の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;
}

最も参考になるコメント

@reeltimedoktor現在、 reconnect_attemptイベントでqueryオブジェクトを更新できるはずです。

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

全てのコメント9件

+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.tokensocket.io.engine.transport.query.tokenなどのさまざまな場所があるようです。 socket.io.opts.query.tokenを設定しても、これらは自動的に入力されません。 ただし、これらを変更しても、サーバーが「見る」ものには影響しません。それでも、古いトークンのみが見えます。

トークンは、ソケットオブジェクトの一部のurlフィールドにURLパラメータとして含まれているようです。 おそらく、これらも更新する必要がありますか?

さらに調査した後、上のトークンを設定しているようですsocket.io.opts.query.token再接続の再認証のためのトークンを変更するのに十分である-何か他のものは、おそらく、私のアプリのためにfirebase認証トークンの生成とは何か問題があると思われます。 したがって、これに遭遇した他の人にとっては、 @ 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"
image

わかりました。修正したと思います。「reconnect_attempt」コールバックで新しいトークンを_同期的に_取得していることを確認する必要があります。つまり、これを行わないでください。

 socket.on('reconnect_attempt', async () => {
      const newToken = await getNewToken(); // won't work
      socket.io.opts.query = {
        token: latestToken,
      };
    });

新しいトークンが設定される前にサーバー側の認証が行われていたようです。 トークンを同期的に取得する場合(以前に取得して保存し、リスナーコールバックで取得するだけで)、サーバーは再接続認証に間に合うように新しい認証トークンを取得します。

同様の問題があります。 しかし、私の現在の回避策は、認証が失敗したときにサーバー側からdisconnectすることです。 クライアントでdisconnectイベントを受信すると、非同期promise呼び出しを使用してクエリ/ヘッダーを再構築します。 reconnectingイベントに到達するまでに、クエリ/ヘッダーに新しい値がすでに含まれています。

将来の読者のために:

Socket.IO v2のqueryオプションの動作は、両方で使用されているため、少し奇妙です。

  • クエリパラメータ(Managerインスタンスの場合)
  • Socket.IOハンドシェイク(ただし、デフォルト以外の名前空間の場合のみ)

したがって、下位互換性のある方法で修正する方法がわかりません...

authオプションを使用できるようになったため、これはSocket.IOv3で修正されていることに注意してください。

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

参照:

このページは役に立ちましたか?
0 / 5 - 0 評価