Socket.io-client: Izinkan socket.handshake.query menjadi fungsi

Dibuat pada 22 Mei 2017  ·  9Komentar  ·  Sumber: socketio/socket.io-client

Yang kamu ingin:

  • [x] laporkan bug
  • [ ] meminta fitur

Perilaku saat ini

socket.handshake.query saat ini memungkinkan data disetel pada connect , tetapi tidak dapat diperbarui dengan referensi sebelum reconnect diaktifkan. Ini menyebabkan masalah saat mengotorisasi koneksi soket dengan token penyegaran.

Langkah-langkah untuk mereproduksi (jika perilaku saat ini adalah bug)

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

Jika server dimulai ulang dan klien reconnect , token mungkin kedaluwarsa saat mengotorisasi ulang soket.

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

Perilaku yang diharapkan

Izinkan kueri menjadi function :

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

Mempersiapkan

  • versi socket.io: 2.0.1

Bagaimana cara memperbaiki

Dalam konstruktor Socket saat ini:

if (opts && opts.query) {
   this.query = opts.query;
}

Dapat diubah menjadi ini:

if(opts && opts.query) {
   this.query = typeof opts.query == 'function' && opts.query.call(this) || opts.query;
}

Komentar yang paling membantu

@reeltimedoktor saat ini Anda harus dapat memperbarui objek query pada acara reconnect_attempt :

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

Semua 9 komentar

+1
perbaikan untuk bug #1086 juga harus menyelesaikan masalah Anda. Mengubah opsi kueri setelah koneksi berhasil berfungsi dengan versi socket.io-client yang lebih lama, tetapi dengan versi saat ini referensi ke objek kueri hilang :(

@reeltimedoktor saat ini Anda harus dapat memperbarui objek query pada acara reconnect_attempt :

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

Solusi @darrachequesne sepertinya tidak berhasil untuk saya :(

Saya menggunakan socket.io-client versi 2.3.0 pada klien, dengan server simpul dengan socket.io versi 2.3.0 .

Pada klien saya melakukan ini:

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

Dan kemudian server mengautentikasi token menggunakan middleware yang diteruskan ke io.use() (yang kemudian akan menyala ketika soket terhubung atau terhubung kembali, afaik?).

Saat ini autentikasi server gagal terhubung kembali, mengatakan bahwa token telah kedaluwarsa - tampaknya token baru tidak ditetapkan dengan benar ke socket.io.opts.query.token - ada ide mengapa?

Terima kasih :)

Pembaruan: Sepertinya ada banyak tempat berbeda di objek soket tempat token auth disimpan, misalnya socket.io.engine.query.token , socket.io.engine.transport.query.token . Ini tidak diisi secara otomatis saat Anda menyetel socket.io.opts.query.token . Namun, mengubah ini tetap tidak memengaruhi apa yang 'dilihat' oleh server - itu masih hanya melihat token lama.

Token juga tampaknya disertakan sebagai parameter URL di beberapa bidang url di objek soket. Mungkin ini perlu diperbarui juga?

Setelah menyelidiki lebih lanjut, tampaknya menyetel token pada socket.io.opts.query.token sudah cukup untuk mengubah token untuk otentikasi ulang saat menghubungkan kembali - sesuatu yang lain tampaknya menjadi masalah untuk aplikasi saya, mungkin ada hubungannya dengan pembuatan token autentikasi firebase. Jadi untuk siapa pun yang menemukan ini, solusi @darrachequesne berfungsi!

Oke, anggap saya sudah memperbaikinya - Anda perlu memastikan bahwa Anda mendapatkan token baru secara sinkron dalam panggilan balik 'reconnect_attempt', yaitu jangan lakukan ini:

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

Sepertinya otentikasi sisi server sedang dilakukan sebelum token baru ditetapkan. Jika Anda mendapatkan token secara sinkron (dengan mengambilnya beberapa saat sebelumnya dan menyimpannya, lalu mengambilnya kembali di callback pendengar), server mendapatkan token autentikasi baru tepat waktu untuk autentikasi koneksi ulang.

dengan "socket.io-client": "3.0.4" saya mendapatkan kesalahan TS2341: Property 'opts' is private and only accessible within class 'Manager'. . Saya menggunakan "typescript": "4.1.3"
image

Oke, anggap saya sudah memperbaikinya - Anda perlu memastikan bahwa Anda mendapatkan token baru _synchronously_ di panggilan balik 'reconnect_attempt', yaitu jangan lakukan ini:

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

Sepertinya otentikasi sisi server sedang dilakukan sebelum token baru ditetapkan. Jika Anda mendapatkan token secara sinkron (dengan mengambilnya beberapa saat sebelumnya dan menyimpannya, lalu mengambilnya kembali di callback pendengar), server mendapatkan token autentikasi baru tepat waktu untuk autentikasi koneksi ulang.

Kami memiliki masalah serupa. Tetapi solusi saya saat ini adalah disconnect dari sisi server ketika auth gagal. setelah menerima acara disconnect pada klien, kami membuat ulang kueri/tajuk dengan panggilan janji asinkron. Pada saat mencapai reconnecting acara, itu sudah memiliki nilai baru di query/header.

Untuk pembaca masa depan:

Perilaku opsi query di Socket.IO v2 agak aneh, karena digunakan di keduanya:

  • parameter kueri (untuk instance Manajer)
  • jabat tangan Socket.IO (tetapi hanya untuk namespace non-default)

Jadi saya tidak yakin bagaimana kita bisa memperbaikinya dengan cara yang kompatibel ke belakang...

Harap dicatat bahwa ini diperbaiki di Socket.IO v3, karena Anda sekarang dapat menggunakan opsi auth :

// plain object
const socket = io({
  auth: {
    token: "abc"
  }
});

// or with a function
const socket = io({
  auth: (cb) => {
    cb({
      token: "abc"
    });
  }
});

Itu harus bekerja dengan fungsi async juga:

const socket = io({
  auth: async (cb) => {
    cb({
      token: "abc"
    });
  }
});

Lihat juga:

Apakah halaman ini membantu?
0 / 5 - 0 peringkat

Masalah terkait

aravindsrivats picture aravindsrivats  ·  4Komentar

ledmago picture ledmago  ·  3Komentar

najibghadri picture najibghadri  ·  7Komentar

zappfinger picture zappfinger  ·  5Komentar

gtk2k picture gtk2k  ·  3Komentar