Token, Token aktualisieren und einen asynchronen Wrapper für eine REST-Anforderung erstellen

Bild In diesem Lernprogramm werden wir kurz untersuchen, wie REST-Anforderungen an die API implementiert werden, für die der Benutzer autorisiert werden muss, und einen asynchronen „Wrapper“ für die Anforderung erstellen, der die Autorisierung überprüft und rechtzeitig aktualisiert.

Anmeldeinformationen


Nachdem wir eine REST-Anfrage an die API gestellt haben, wo wir den Login und das Passwort gesendet haben, erhalten wir im Gegenzug json des folgenden Formats (die Werte sind zufällig und die Zeilen sind normalerweise länger):

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

Die Antwort enthält möglicherweise mehr Felder , z. B. "token_type" , "expires_on" usw. Für diese Implementierung benötigen wir jedoch nur die drei oben genannten Felder.
Schauen wir sie uns genauer an:

  • access_token - das Token, das wir im Header jeder Anforderung senden müssen, um Daten als Antwort zu erhalten
  • refresh_token - das Token, das wir senden müssen, um ein neues Token zu erhalten, wenn das alte abläuft
  • expires_in - Token-Lebensdauer in Sekunden

Token empfangen


Erstellen Sie nun eine Funktion, die den oben beschriebenen JSON empfängt, und speichern Sie ihn.

Wir speichern Daten zur Autorisierung je nach Bedarf in sessionStorage oder localStorage . Im ersten Fall werden die Daten gespeichert, bis der Benutzer die Sitzung beendet oder den Browser schließt. Im zweiten Fall werden die Daten unbegrenzt im Browser gespeichert, bis der localStorage aus irgendeinem Grund gelöscht wird.

Funktion zum Speichern des Tokens in sessionStorage:


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

Funktion zum Empfangen eines Tokens:


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

Daher haben wir ein Token mit den Feldern "access_token" , "refresh_token" und "expires_in" erhalten und zur weiteren Verwendung in sessionStorage gespeichert.

Token-Update


Das Token, das wir zuvor erhalten haben, hat eine begrenzte Lebensdauer, die im Feld "expires_in" festgelegt ist. Nach Ablauf seiner Lebensdauer kann der Benutzer keine neuen Daten empfangen, indem er dieses Token in der Anforderung sendet. Daher müssen Sie ein neues Token erhalten.

Wir können das Token auf zwei Arten erhalten: Die erste Möglichkeit besteht darin, sich erneut anzumelden, indem Sie den Benutzernamen und das Kennwort an den Server senden. Dies passt jedoch nicht zu uns, da es falsch ist, den Benutzer zu zwingen, die Berechtigungsdaten jedes Mal nach einem bestimmten Zeitraum erneut einzugeben - dies sollte automatisch erfolgen. Das Speichern eines Login / Passwort-Paares irgendwo im Speicher für das automatische Senden ist jedoch unsicher. Deshalb benötigen wir ein refresh_token , das zuvor mit access_token empfangen und in sessionStorage gespeichert wurde. Durch Senden dieses Tokens an eine andere von der API bereitgestellte Adresse können wir als Antwort ein neues "frisches" Token erhalten.

Funktion für Token Update


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

Mit dem obigen Code haben wir das Token in sessionStorage neu geschrieben und können nun auf neue Weise Anforderungen an die API senden.

Erstellen einer Wrapper-Funktion


Jetzt erstellen wir eine Funktion, die dem Anforderungsheader Berechtigungsdaten hinzufügt und diese bei Bedarf automatisch aktualisiert, bevor die Anforderung gestellt wird.

Wenn das Token abgelaufen ist und wir ein neues Token anfordern müssen, ist unsere Funktion asynchron. Dazu verwenden wir das Konstrukt async / await.

Wrapper-Funktion


 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 } 

Mit dem obigen Code haben wir eine Funktion erstellt, die Anforderungen in der API ein Token hinzufügt. Mit dieser Funktion können wir das Abrufen in den benötigten Abfragen ersetzen, wenn eine Autorisierung erforderlich ist, und dafür müssen wir die Syntax nicht ändern oder den Argumenten keine weiteren Daten hinzufügen.
Es reicht gerade aus, es in eine Datei zu „importieren“ und den Standardabruf dadurch zu ersetzen.

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

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


All Articles