2016-03-09 21 views
18

Implementazione dell'autenticazione token nella mia app Web. Il mio access token scade ogni N minuti e viene utilizzato per accedere a refresh token e ottenere un nuovo access token.Interceptor Axios e accesso asincrono

Io uso Axios per tutte le mie chiamate API. Ho un intercettore configurato per intercettare le risposte 401.

axios.interceptors.response.use(undefined, function (err) { 
    if (err.status === 401 && err.config && !err.config.__isRetryRequest) { 
    serviceRefreshLogin(
     getRefreshToken(), 
     success => { setTokens(success.access_token, success.refresh_token) }, 
     error => { console.log('Refresh login error: ', error) } 
    ) 
    err.config.__isRetryRequest = true 
    err.config.headers.Authorization = 'Bearer ' + getAccessToken() 
    return axios(err.config); 
    } 
    throw err 
}) 

In sostanza, come ho intercettare una risposta 401, voglio fare un login e di ripetere la richiesta rifiutata originale con i nuovi token. La mia funzione serviceRefreshLogin chiama setAccessToken() nel suo blocco then. Ma il problema è che il blocco then si verifica dopo il getAccessToken() nell'intercettore, quindi il tentativo si verifica con le vecchie credenziali scadute.

getAccessToken() e getRefreshToken() restituiscono semplicemente i token esistenti memorizzati nel browser (gestiscono localStorage, cookie, ecc.).

Come farei a garantire che le dichiarazioni non vengano eseguite finché non viene restituita una promessa?

(Qui è un problema corrispondente su GitHub: https://github.com/mzabriskie/axios/issues/266)

risposta

14

Basta usare un'altra promessa: D

axios.interceptors.response.use(undefined, function (err) { 
    return new Promise(function (resolve, reject) { 
     if (err.status === 401 && err.config && !err.config.__isRetryRequest) { 
      serviceRefreshLogin(
       getRefreshToken(), 
       success => { 
         setTokens(success.access_token, success.refresh_token) 
         err.config.__isRetryRequest = true 
         err.config.headers.Authorization = 'Bearer ' + getAccessToken(); 
         axios(err.config).then(resolve, reject); 
       }, 
       error => { 
        console.log('Refresh login error: ', error); 
        reject(error); 
       } 
      ); 
     } 
     throw err; 
    }); 
}); 

Se il vostro ambiente non suport promesse usano polyfill, ad esempio https://github.com/stefanpenner/es6-promise

Ma , potrebbe essere meglio riscrivere getRefreshToken per restituire la promessa e quindi semplificare il codice

axios.interceptors.response.use(undefined, function (err) { 

     if (err.status === 401 && err.config && !err.config.__isRetryRequest) { 
      return getRefreshToken() 
      .then(function (success) { 
       setTokens(success.access_token, success.refresh_token) ;     
       err.config.__isRetryRequest = true; 
       err.config.headers.Authorization = 'Bearer ' + getAccessToken(); 
       return axios(err.config); 
      }) 
      .catch(function (error) { 
       console.log('Refresh login error: ', error); 
       throw error; 
      }); 
     } 
     throw err; 
}); 

Demo https://plnkr.co/edit/0ZLpc8jgKI18w4c0f905?p=preview

+0

Sfortunatamente non funziona come intercettore. Quando provo questo, la richiesta viene ritentata solo DOPO che la promessa originale viene rifiutata. –

+0

ho fatto plunkr https://plnkr.co/edit/0ZLpc8jgKI18w4c0f905?p=preview – ForceUser

+0

Spiacente, ho aggiunto un chiarimento - Non vedo molto senso nel rendere getRefreshToken() in una promessa. È una funzione che gestisce le cose locali per il browser - c'è sempre qualcosa disponibile lì. Il token di aggiornamento non scade mai BTW. –