Token, segarkan token, dan buat pembungkus asinkron untuk permintaan REST

gambar Dalam tutorial ini, kami akan meninjau secara singkat bagaimana permintaan REST ke API diimplementasikan yang mengharuskan pengguna untuk diotorisasi, dan membuat "pembungkus" asinkron untuk permintaan tersebut, yang akan memeriksa otorisasi dan memperbaruinya secara tepat waktu.

Informasi Login


Setelah membuat permintaan REST ke api, tempat kami mengirim login dan kata sandi, sebagai imbalannya kami mendapatkan json dengan format berikut (nilainya acak dan garis biasanya lebih panjang):

{ "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSld", "refresh_token": "1eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgS", "expires_in": 124234149563 } 

Mungkin ada lebih banyak bidang dalam respons, misalnya, "token_type" , "expires_on" , dll., Tetapi, untuk implementasi ini, kami hanya memerlukan tiga bidang di atas.
Mari kita lihat lebih dekat:

  • access_token - token yang perlu kami kirim di header setiap permintaan untuk menerima data sebagai respons
  • refresh_token - token yang perlu kami kirim untuk menerima token baru ketika yang lama kedaluwarsa
  • expires_in - token seumur hidup dalam hitungan detik

Menerima token


Sekarang buat fungsi yang akan menerima json yang dijelaskan di atas dan simpan.

Kami akan menyimpan data untuk otorisasi di sessionStorage atau localStorage , tergantung pada kebutuhan kami. Dalam kasus pertama, data disimpan sampai pengguna menyelesaikan sesi atau menutup browser, dalam kasus kedua, data akan disimpan di browser untuk waktu yang tidak terbatas hingga karena alasan penyimpanan lokal dihapus.

Berfungsi untuk menyimpan token di sessionStorage:


 function saveToken(token) { sessionStorage.setItem('tokenData', JSON.stringify(token)); } 

Fungsi untuk menerima token:


 function getTokenData(login, password) { return fetch('api/auth', { method: 'POST', credentials: 'include', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ login, password, }), }) .then((res) => { if (res.status === 200) { const tokenData = res.json(); saveToken(JSON.stringify(tokenData)); //     sessionStorage,   ,   return Promise.resolve() } return Promise.reject(); }); } 

Jadi, kami menerima token dengan bidang "access_token" , "refresh_token" dan "expires_in" dan menyimpannya di sessionStorage untuk digunakan lebih lanjut.

Pembaruan Token


Token yang kami terima sebelumnya memiliki masa pakai terbatas, yang ditetapkan di bidang "expires_in" . Setelah masa pakainya berakhir, pengguna tidak akan dapat menerima data baru dengan mengirimkan token ini dalam permintaan, jadi Anda perlu mendapatkan token baru.

Kita bisa mendapatkan token dengan dua cara: cara pertama adalah masuk lagi dengan mengirimkan nama pengguna dan kata sandi ke server. Tetapi ini tidak cocok untuk kami, karena memaksa pengguna untuk memasukkan kembali data otorisasi setiap kali setelah periode waktu tertentu salah - ini harus dilakukan secara otomatis. Tetapi menyimpan pasangan login / kata sandi di suatu tempat di memori untuk pengiriman otomatis tidak aman, itu sebabnya kita memerlukan refresh_token , yang diterima sebelumnya dengan access_token dan disimpan di sessionStorage. Dengan mengirimkan token ini ke alamat lain yang disediakan api, kita bisa mendapatkan token "segar" baru sebagai tanggapan.

Fungsi untuk Pembaruan Token


 function refreshToken(token) { return fetch('api/auth/refreshToken', { method: 'POST', credentials: 'include', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', }, body: JSON.stringify({ token, }), }) .then((res) => { if (res.status === 200) { const tokenData = res.json(); saveToken(JSON.stringify(tokenData)); //      sessionStorage,   ,   return Promise.resolve(); } return Promise.reject(); }); } 

Dengan menggunakan kode di atas, kami menulis ulang token di sessionStorage dan sekarang kami dapat mengirim permintaan ke api dengan cara baru.

Membuat fungsi pembungkus


Sekarang kami membuat fungsi yang akan menambahkan data otorisasi ke header permintaan, dan jika perlu, perbarui secara otomatis sebelum mengajukan permintaan.

Karena jika token telah kedaluwarsa, kami perlu meminta token baru, maka fungsi kami akan tidak sinkron. Untuk ini kita akan menggunakan konstruk async / wait.

Fungsi pembungkus


 export async function fetchWithAuth(url, options) { const loginUrl = '/login'; // url    let tokenData = null; //    tokenData if (sessionStorage.authToken) { //   sessionStorage  tokenData,    tokenData = JSON.parse(localStorage.tokenData); } else { return window.location.replace(loginUrl); //   ,       } if (!options.headers) { //     headers,    options.headers = {}; } if (tokenData) { if (Date.now() >= tokenData.expires_on * 1000) { //        try { const newToken = await refreshToken(tokenData.refresh_token); //  ,      refresh_token saveToken(newToken); } catch () { //   -   ,       return window.location.replace(loginUrl); } } options.headers.Authorization = `Bearer ${tokenData.token}`; //    headers  } return fetch(url, options); //   ,       headers } 

Menggunakan kode di atas, kami membuat fungsi yang akan menambahkan token ke permintaan dalam api. Dengan fungsi ini, kita dapat mengganti pengambilan dalam kueri yang kita butuhkan, di mana diperlukan otorisasi dan untuk ini kita tidak perlu mengubah sintaks atau menambahkan data lagi ke argumen.
Itu hanya akan cukup untuk "mengimpor" ke dalam file dan mengganti pengambilan standar dengan itu.

 import fetchWithAuth from './api'; function getData() { return fetchWithAuth('api/data', options) } 

Source: https://habr.com/ru/post/id456188/


All Articles