with vanilla started sincrono library interceptors guide getting javascript ajax authentication promise axios

javascript - vanilla - patch axios



Interceptores de Axios e inicio de sesión asíncrono. (2)

Estoy implementando la autenticación de token en mi aplicación web. Mi access token caduca cada N minutos y luego se usa un refresh token para iniciar sesión y obtener un nuevo access token .

Yo uso Axios para todas mis llamadas a la API. Tengo un interceptor configurado para interceptar 401 respuestas.

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

Básicamente, cuando intercepto una respuesta 401, quiero iniciar sesión y luego reintentar la solicitud original rechazada con los nuevos tokens. Mi función setAccessToken() llama a setAccessToken() en su bloque de then . Pero el problema es que el bloque de ese then ocurre más tarde que el getAccessToken() en el interceptor, por lo que el reintento ocurre con las credenciales caducadas.

getAccessToken() y getRefreshToken() simplemente devuelven los tokens existentes almacenados en el navegador (administran el almacenamiento local, las cookies, etc.).

¿Cómo me aseguraría de que las declaraciones no se ejecuten hasta que se devuelva una promesa?

(Aquí hay un problema correspondiente en github: https://github.com/mzabriskie/axios/issues/266 )


Podría hacerlo en la solicitud en lugar de la respuesta, y probablemente estaría más limpio, ya que evitaría golpear el servidor cuando el token de acceso haya caducado. Copiando de este artículo :

function issueToken() { return new Promise((resolve, reject) => { return client({ ... }).then((response) => { resolve(response); }).catch((err) => { reject(err); }); }); } client.interceptors.request.use((config) => { let originalRequest = config; if (tokenIsExpired && path_is_not_login) { return issueToken().then((token) => { originalRequest[''Authorization''] = ''Bearer '' + token; return Promise.resolve(originalRequest); }); } return config; }, (err) => { return Promise.reject(err); });


Solo usa otra promesa: 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; }); });

Si su entorno no cumple con las promesas, use polyfill, por ejemplo, https://github.com/stefanpenner/es6-promise

Pero, puede ser mejor reescribir getRefreshToken para devolver una promesa y luego simplificar el código

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

Demostración https://plnkr.co/edit/0ZLpc8jgKI18w4c0f905?p=preview