Saltar al contenido

¿Cómo manejar 401 (error de autenticación) en axios y reaccionar?

Basta ya de indagar por todo internet porque llegaste al espacio necesario, poseemos la respuesta que quieres y sin problemas.

Solución:

Si desea utilizar interceptores para manejar el error 401, aquí está el fragmento de código.

axios.interceptors.response.use(response => 
   return response;
, error => 
  if (error.response.status === 401) 
   //place your reentry code
  
  return error;
);

Lo tengo funcionando con el siguiente código

import axios from 'axios';
import config from '../../configuration.json';
import qs from 'qs';

const baseURL = config['baseUrl_local'];
let authTokenRequest;

/**
  * @description axios instance for ajax requests
*/ 

var client = axios.create(
baseURL: baseURL,
headers: 
    appID: 8,
    version: "1.1.0",
    empID: localStorage.getItem('empID'),
    token: localStorage.getItem('accessToken')

);

/**
 * @description this method calls a requestNewToken method to issue a 
 new token to the client
*/ 

 function getAuthToken() 
   if (!authTokenRequest) 
   authTokenRequest = requestNewToken();
   authTokenRequest.then(resetAuthTokenRequest, resetAuthTokenRequest);
 
 return authTokenRequest;
 

/**
  * @description this method requests the server to issue a new token, 
  the server response is updated in local storage accessToken
*/ 

function requestNewToken() 
  var newToken = request(
  method: "post",
  url: '/sign-in',
  data:  qs.stringify(
         "userName":localStorage.getItem('userName'),
         "password":localStorage.getItem('password')
         )  
  ).then((res)=>
  if(res.status == "success")
    localStorage.setItem('accessToken',res.data.accessToken);
    //if featureArray is present in response object, update the 
    featureArray in local storage
    if(res.data.features)
      localStorage.setItem(
      'featureArray',
     JSON.stringify(res.data.features));
    
    client = axios.create(
     baseURL: baseURL,
     headers: 
          appID: 8,
          version: "1.1.0",
          empID: localStorage.getItem('empID'),
          token: localStorage.getItem('accessToken')
      
   );
  else 
  window.location = "/logout";
 
);
 return newToken;


function resetAuthTokenRequest() 
  authTokenRequest = null;
 

/**
  * @description if any of the API gets 401 status code, this method 
   calls getAuthToken method to renew accessToken
  * updates the error configuration and retries all failed requests 
  again
*/ 

client.interceptors.response.use(undefined, err => 
  const error = err.response;
  // if error is 401 
  if (error.status===401 && error.config && 
  !error.config.__isRetryRequest) 
  // request for a new token
  return getAuthToken().then(response => 
   // update the error config with new token
   error.config.__isRetryRequest = true;
   error.config.headers.token= localStorage.getItem("accessToken");
   return client(error.config);
  );
  
);

/**
 * @description wrapper for making ajax requests
 * @param object object with method,url,data etc.
*/ 

const request = function(options) 
  const onSuccess = function(response) 
    return response.data;
  
 const onError = function(error)  error.message);
 

return client(options)
        .then(onSuccess)
        .catch(onError);
        options


export default request;

[EDIT] Es 2019, aquí hay otra implementación para lo mismo. La solución anterior es excelente, pero no funciona bien con múltiples solicitudes fallidas, a su vez, también llama a getToken con el token actualizado.

 import axios from "axios";

 /* @internal */
 import config from "../config";
 import TokenService from "./token_service";

class Request 
    constructor() 
        this.baseURL = config.baseUrl;
        this.isRefreshing = false;
        this.failedRequests = [];
        this.tokenService = new TokenService();
        this.client = axios.create(
            baseURL: config.apiServerBaseUrl,
            headers: 
               clientSecret: this.clientSecret,
            ,
        );
        this.beforeRequest = this.beforeRequest.bind(this);
        this.onRequestFailure = this.onRequestFailure.bind(this);
        this.processQueue = this.processQueue.bind(this);
        this.client.interceptors.request.use(this.beforeRequest);
        this.client.interceptors.response.use(this.onRequestSuccess, 
this.onRequestFailure);


beforeRequest(request) 
    const token = TokenService.getAccessToken();
    request.headers.Authorization = `Token $token`;
    return request;


static onRequestSuccess(response) 
    return response.data;


async onRequestFailure(err) 
    const  response  = err;
    if (response.status === 401 && err && err.config && !err.config.__isRetryRequest) 
        if (this.isRefreshing) 
            try 
                const token = await new Promise((resolve, reject) => 
                    this.failedRequests.push( resolve, reject );
                );
                err.config.headers.Authorization = `Bearer $token`;
                return this.client(err.config);
            
            catch (e) 
                return e;
            
        
        this.isRefreshing = true;
        err.config.__isRetryRequest = true;
        return new Promise((resolve, reject) => 
            this.tokenService.refreshAccessToken().then((token) => 
                this.tokenService.setAccessToken(token);
                err.config.headers.Authorization = `Bearer $token`;
                this.isRefreshing = false;
                this.processQueue(null, token);
                resolve(this.client(err.config));
            ).catch((e) => 
                this.processQueue(e, null);
                reject(err.response);
            );
        );
    
    throw response;


processQueue(error, token = null) 
    this.failedRequests.forEach((prom) => 
        if (error) 
            prom.reject(error);
         else 
            prom.resolve(token);
        
       );
        this.failedRequests = [];
    



const request = new Request();

export default request.client;

Esto funciona:

// Add a 401 response interceptor
window.axios.interceptors.response.use(function (response) 
    return response;
, function (error) 
    if (401 === error.response.status) 
        // handle error: inform user, go to login, etc
     else 
        return Promise.reject(error);
    
);

Extraído de: https://gist.github.com/yajra/5f5551649b20c8f668aec48549ef5c1f

Tuve este problema adicional:

“Error de red” sin respuesta

tl; dr – Fue un problema con CORS y cómo se configuró, por lo que axios nunca recuperó la información del navegador. Tienes que resolverlo desde el lado del servidor.

Descripción

si tiene un problema similar, lo verá en la consola del navegador. El navegador le impedirá acceder a una URL diferente a través de ajax.

En mi caso particular (node.js – express) fue el orden del filtro, el filtro CORS (entorno de desarrollo) se agregó después del controlador para esta solicitud en particular, por lo que el servidor no estaba enviando los encabezados CORS adecuados en ese momento y por lo tanto, el navegador ni siquiera permitía que se realizara la solicitud (no hubo ninguna llamada al servidor, por lo que no se devolvió ningún objeto de error).

Reseñas y calificaciones

Acuérdate de que tienes la capacidad de comentar .

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *