2016-03-09 32 views
18

Wprowadzam uwierzytelnianie tokenowe w mojej aplikacji internetowej. Mój access token wygasa co N minut, a niż refresh token jest używany do logowania i uzyskiwania nowego access token.Przechwytywacze Axios i logowanie asynchroniczne

Używam Axios do wszystkich moich wywołań API. Mam zestaw przechwytywania skonfigurowany do przechwytywania odpowiedzi 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 
}) 

Zasadniczo, jak przechwycić odpowiedź 401, chcę zrobić login i ponowić niż oryginalny odrzucił wniosek z nowymi żetonami. Moja funkcja wywołuje setAccessToken() w swoim bloku then. Problem polega jednak na tym, że blok zdarza się później niż getAccessToken() w przechwytywaczu, więc próba jest wykonywana ze starymi wygasłymi poświadczeniami.

getAccessToken() i getRefreshToken() po prostu zwracają istniejące tokeny przechowywane w przeglądarce (zarządzają localStorage, cookies, itp.).

Co powinienem zrobić, aby oświadczenia nie były wykonywane, dopóki obietnica nie wróci?

(Oto odpowiedni problem na github: https://github.com/mzabriskie/axios/issues/266)

Odpowiedz

14

prostu użyć innego obietnicę: 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; 
    }); 
}); 

Jeśli środowisko nie suport obietnice używać PolyFill np https://github.com/stefanpenner/es6-promise

Ale , lepiej jest przepisać getRefreshToken, aby zwrócić obietnicę, a następnie uprościć kod:

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

Niestety to nie działa jako przechwytywacz. Kiedy próbuję tego, prośba zostanie powtórzona dopiero po tym, jak pierwotna obietnica zostanie odrzucona. –

+0

Zrobiłem plunkr https://plnkr.co/edit/0ZLpc8jgKI18w4c0f905?p=preview – ForceUser

+0

Przepraszamy, dodano wyjaśnienie - nie widzę sensu w podejmowaniu getRefreshToken() w obietnicy. Jest to funkcja, która zarządza materiałem lokalnym w przeglądarce - zawsze jest tam coś dostępnego. Odświeżenie tokena nigdy nie wygasa BTW. –