Perangkap token telah melanda sebuah laman web yang sedang aktif apabila lima tab yang dibuka oleh seorang pengguna cuba menyegarkan JWT yang telah tamat tempoh pada milisaat yang sama, membanjiri backend dengan permintaan penyegaran pendua dan membatalkan sesi tersebut serta-merta. Setiap tab log keluar pengguna, membuktikan bahawa penyelesaian satu-tab untuk pembaharuan token tidak lagi mencukupi.
Mengapa perangkap token ini penting
Aplikasi satu halaman (SPA) moden menggunakan token akses jangka pendek dan refresh token jangka panjang. Apabila token akses tamat tempoh, klien menghantar permintaan penyegaran, menerima pasangan token baharu, dan mencuba semula panggilan asal. Kebanyakan pembangun melindungi aliran ini dengan bendera dalam memori (contohnya, isRefreshing = true) atau barisan permintaan (request queue), dan mengujinya dalam satu tab sahaja. Dalam dunia nyata, pengguna mengekalkan beberapa tab yang terbuka: halaman tetapan, papan pemuka analitik, dan beberapa paparan data. Apabila token akses tamat tempoh, setiap tab mengesan ralat 401 secara bebas, setiap satu melancarkan permintaan penyegaran, dan backend—terutamanya apabila ia menguatkuasakan putaran refresh-token (refresh-token rotation)—menganggap permintaan kedua sebagai serangan ulangan (replay) dan membatalkan keseluruhan sesi.
Pengasingan JavaScript mewujudkan masalah
Setiap tab pelayar menjalankan konteks JavaScript tersendiri. Pemboleh ubah, pemasa, dan bendera dalam memori tidak kelihatan kepada tab lain, walaupun mereka berkongsi asal (origin) yang sama. Bendera yang menyatakan “penyegaran sedang dalam proses” hanya wujud di dalam tab yang menetapkannya. Tab lain tidak mempunyai cara untuk mengetahui bahawa token sedang disegarkan di tempat lain, jadi mereka semua melancarkan panggilan rangkaian mereka sendiri. Isu ini bukanlah pepijat (bug) dalam interceptor; ia adalah had asas pengasingan keadaan (state isolation) bahagian klien.
Web Locks API sebagai penyelamat
Apabila sesebuah tab memegang kunci (lock), mana-mana tab lain yang meminta kunci yang sama mesti menunggu sehingga ia dilepaskan.
Cara ia berfungsi untuk penyegaran token
- Mengesan 401 – Mana-mana tab yang menerima respons tanpa kebenaran akan memanggil
navigator.locks.request('auth_token_refresh_lock', async lock => { … }). - Memperoleh kunci – Jika tiada tab lain memegang kunci tersebut, tab semasa akan meneruskan proses; jika tidak, ia akan berhenti seketika sehingga kunci tersedia.
- Segarkan sekali – Pemegang kunci menghantar permintaan penyegaran, menyimpan token akses baharu dan cap masa (timestamp) dalam
localStorage, dan kemudian melepaskan kunci secara automatik apabila fungsi callback selesai. - Langkau kerja pendua – Apabila tab yang menunggu akhirnya mendapat kunci, ia membaca cap masa daripada
localStorage. Jika token telah disegarkan dalam tempoh yang boleh dikonfigurasi (contohnya, beberapa saat yang lalu), tab tersebut akan melangkau panggilan rangkaian dan mengemas kini token dalam memorinya daripadalocalStorage. - Kendalikan kegagalan (crash) – Jika sesebuah tab mengalami kegagalan atau ditutup semasa memegang kunci, pelayar akan melepaskan kunci tersebut, membolehkan tab lain mencuba semula penyegaran.
Kelebihan secara ringkas
- Sifar panggilan rangkaian yang berlebihan – Hanya tab pertama yang berkomunikasi dengan backend.
- Tiada pemusnahan sesi – Putaran refresh-token hanya melihat penggunaan tunggal, memastikan sesi kekal aktif.
- Pemulihan yang lancar – Pelepasan kunci yang diuruskan oleh pelayar menghalang deadlock jika sesebuah tab hilang.
Senarai semak pelaksanaan
- Bungkus logik penyegaran dalam interceptor Axios (atau fetch) anda dengan permintaan kunci (lock request).
- Simpan token yang telah disegarkan dan cap masa milisaat dalam
localStorage(atausessionStoragejika anda lebih suka data mengikut sesi). - Apabila kunci diberikan, bandingkan cap masa yang disimpan dengan
Date.now(). Jika perbezaannya di bawah ambang (threshold) anda, baca token daripada storan dan bukannya memanggil backend. - Pastikan interceptor mengemas kini pengepala (header) permintaan dengan token yang diambil daripada storan sebelum mencuba semula panggilan API asal.
- Uji aliran tersebut dengan berbilang tab, simulasi kependaman (latency) rangkaian untuk mengesahkan bahawa hanya satu permintaan penyegaran sahaja yang sampai ke pelayan.
Apa yang mungkin salah
Apa yang perlu diperhatikan seterusnya
Kesimpulan
Anggap setiap tab pelayar sebagai satu nod dalam sistem teragih yang kecil. Dengan menggunakan Web Locks API untuk menyusun (serialize) penyegaran JWT, anda menghapuskan panggilan pendua, melindungi putaran refresh-token, dan memastikan pengguna kekal log masuk merentasi semua tab yang terbuka.
