Fügen Sie den Autorisierungsheader für alle Axios-Anforderungen hinzu


125

Ich habe eine React / Redux-Anwendung, die ein Token von einem API-Server abruft. Nachdem sich der Benutzer authentifiziert hat, möchte ich, dass alle Axios-Anforderungen dieses Token als Autorisierungsheader haben, ohne es manuell an jede Anforderung in der Aktion anhängen zu müssen. Ich bin ziemlich neu in der Reaktion / Redux und bin mir nicht sicher, wie ich am besten vorgehen soll. Ich finde keine hochwertigen Treffer bei Google.

Hier ist mein Redux-Setup:

// actions.js
import axios from 'axios';

export function loginUser(props) {
  const url = `https://api.mydomain.com/login/`;
  const { email, password } = props;
  const request = axios.post(url, { email, password });

  return {
    type: LOGIN_USER,
    payload: request
  };
}

export function fetchPages() {
  /* here is where I'd like the header to be attached automatically if the user
     has logged in */ 
  const request = axios.get(PAGES_URL);

  return {
    type: FETCH_PAGES,
    payload: request
  };
}

// reducers.js
const initialState = {
  isAuthenticated: false,
  token: null
};

export default (state = initialState, action) => {
  switch(action.type) {
    case LOGIN_USER:
      // here is where I believe I should be attaching the header to all axios requests.
      return {
        token: action.payload.data.key,
        isAuthenticated: true
      };
    case LOGOUT_USER:
      // i would remove the header from all axios requests here.
      return initialState;
    default:
      return state;
  }
}

Mein Token wird im Redux Store unter gespeichert state.session.token.

Ich bin ein bisschen verloren, wie ich vorgehen soll. Ich habe versucht, eine Axios-Instanz in einer Datei in meinem Stammverzeichnis zu erstellen und diese anstelle von node_modules zu aktualisieren / importieren, aber der Header wird nicht angehängt, wenn sich der Status ändert. Alle Rückmeldungen / Ideen werden sehr geschätzt, danke.


Wo speichern Sie das Autorisierungstoken, nachdem das Token vom Server empfangen wurde? lokaler Speicher?
Hardik Modha

in Redux Store session.token
awwester

Antworten:


195

Es gibt mehrere Möglichkeiten, dies zu erreichen. Hier habe ich die beiden häufigsten Ansätze erläutert.

1. Sie können Axios Interceptors verwenden , um Anforderungen abzufangen und Autorisierungsheader hinzuzufügen.

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    const token = store.getState().session.token;
    config.headers.Authorization =  token;

    return config;
});

2. Aus der Dokumentation von können axiosSie ersehen, dass ein Mechanismus verfügbar ist, mit dem Sie den Standardheader festlegen können, der bei jeder von Ihnen gestellten Anfrage gesendet wird.

axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;

Also in deinem Fall:

axios.defaults.headers.common['Authorization'] = store.getState().session.token;

Wenn Sie möchten, können Sie eine selbstausführbare Funktion erstellen, die den Autorisierungsheader selbst festlegt, wenn das Token im Speicher vorhanden ist.

(function() {
     String token = store.getState().session.token;
     if (token) {
         axios.defaults.headers.common['Authorization'] = token;
     } else {
         axios.defaults.headers.common['Authorization'] = null;
         /*if setting null does not remove `Authorization` header then try     
           delete axios.defaults.headers.common['Authorization'];
         */
     }
})();

Jetzt müssen Sie das Token nicht mehr manuell an jede Anforderung anhängen. Sie können die obige Funktion in die Datei einfügen, die garantiert jedes Mal ausgeführt wird ( z. B.: Datei, die die Routen enthält).

Ich hoffe es hilft :)


1
Ich benutze bereits Redux-Persist, werde mir aber die Middleware ansehen, um das Token im Header anzuhängen. Danke!
Awwester

1
@awwester Sie benötigen keine Middleware, um das Token im Header anzuhängen. Das Anhängen eines Tokens im Header ist axios.defaults.header.common[Auth_Token] = tokenso einfach.
Hardik Modha

4
@HardikModha Ich bin gespannt, wie man das mit der Fetch API machen kann.
Rowland

@Rowland Ich glaube, Sie müssen einen Wrapper über die Fetch-API schreiben, um dasselbe zu erreichen. Die ausführliche Antwort auf diese Frage liegt außerhalb des Rahmens der vom OP gestellten Frage. Sie können eine andere Frage stellen :)
Hardik Modha

1
Hallo @HardikModha. Wenn ich die Standardheader für das gesetzte Token verwende, wenn ich das Token erneuern möchte, kann es nicht erneut in den Header gesetzt werden. ist es richtig? Also muss ich die Abfangjäger benutzen.
Anfänger Entwickler

47

Wenn Sie die Version "axios": "^ 0.17.1" verwenden, können Sie Folgendes tun:

Instanz von Axios erstellen:

// Default config options
  const defaultOptions = {
    baseURL: <CHANGE-TO-URL>,
    headers: {
      'Content-Type': 'application/json',
    },
  };

  // Create instance
  let instance = axios.create(defaultOptions);

  // Set the AUTH token for any request
  instance.interceptors.request.use(function (config) {
    const token = localStorage.getItem('token');
    config.headers.Authorization =  token ? `Bearer ${token}` : '';
    return config;
  });

Dann wird für jede Anforderung das Token aus localStorage ausgewählt und den Anforderungsheadern hinzugefügt.

Ich verwende dieselbe Instanz in der gesamten App mit diesem Code:

import axios from 'axios';

const fetchClient = () => {
  const defaultOptions = {
    baseURL: process.env.REACT_APP_API_PATH,
    method: 'get',
    headers: {
      'Content-Type': 'application/json',
    },
  };

  // Create instance
  let instance = axios.create(defaultOptions);

  // Set the AUTH token for any request
  instance.interceptors.request.use(function (config) {
    const token = localStorage.getItem('token');
    config.headers.Authorization =  token ? `Bearer ${token}` : '';
    return config;
  });

  return instance;
};

export default fetchClient();

Viel Glück.


@ NguyễnPhúc Mit Vergnügen geht es darum, "Abfangjäger" von Axios zu verwenden
Uhr

45

Die beste Lösung für mich besteht darin, einen Client-Service zu erstellen, den Sie mit Ihrem Token instanziieren und zum Umschließen verwenden axios.

import axios from 'axios';

const client = (token = null) => {
    const defaultOptions = {
        headers: {
            Authorization: token ? `Token ${token}` : '',
        },
    };

    return {
        get: (url, options = {}) => axios.get(url, { ...defaultOptions, ...options }),
        post: (url, data, options = {}) => axios.post(url, data, { ...defaultOptions, ...options }),
        put: (url, data, options = {}) => axios.put(url, data, { ...defaultOptions, ...options }),
        delete: (url, options = {}) => axios.delete(url, { ...defaultOptions, ...options }),
    };
};

const request = client('MY SECRET TOKEN');

request.get(PAGES_URL);

In diesem Client können Sie das Token auch wie gewünscht aus dem localStorage / Cookie abrufen.


1
Was ist, wenn Sie die request.get () mit "application-type" -Headern erstellen möchten? Bei Ihrem Ansatz werden die Header von defaultOptions von den Headern von request überschrieben. Ich habe recht? Danke dir.
Nipuro

9

Ebenso haben wir eine Funktion zum Setzen oder Löschen des Tokens aus Aufrufen wie diesen:

import axios from 'axios';

export default function setAuthToken(token) {
  axios.defaults.headers.common['Authorization'] = '';
  delete axios.defaults.headers.common['Authorization'];

  if (token) {
    axios.defaults.headers.common['Authorization'] = `${token}`;
  }
}

Wir bereinigen immer das vorhandene Token bei der Initialisierung und richten dann das empfangene ein.


5

Wenn Sie in Zukunft andere API-Routen aufrufen und Ihr Token im Store behalten möchten, versuchen Sie , Redux-Middleware zu verwenden .

Die Middleware könnte auf die API-Aktion warten und API-Anforderungen entsprechend über Axios senden.

Hier ist ein sehr einfaches Beispiel:

Aktionen / api.js

export const CALL_API = 'CALL_API';

function onSuccess(payload) {
  return {
    type: 'SUCCESS',
    payload
  };
}

function onError(payload) {
  return {
    type: 'ERROR',
    payload,
    error: true
  };
}

export function apiLogin(credentials) {
  return {
    onSuccess,
    onError,
    type: CALL_API,
    params: { ...credentials },
    method: 'post',
    url: 'login'
  };
}

Middleware / api.js.

import axios from 'axios';
import { CALL_API } from '../actions/api';

export default ({ getState, dispatch }) => next => async action => {
  // Ignore anything that's not calling the api
  if (action.type !== CALL_API) {
    return next(action);
  }

  // Grab the token from state
  const { token } = getState().session;

  // Format the request and attach the token.
  const { method, onSuccess, onError, params, url } = action;

  const defaultOptions = {
    headers: {
      Authorization: token ? `Token ${token}` : '',
    }
  };

  const options = {
    ...defaultOptions,
    ...params
  };

  try {
    const response = await axios[method](url, options);
    dispatch(onSuccess(response.data));
  } catch (error) {
    dispatch(onError(error.data));
  }

  return next(action);
};

3

Manchmal tritt ein Fall auf, in dem einige der mit Axios gestellten Anforderungen auf Endpunkte verweisen, die keine Autorisierungsheader akzeptieren. Daher ist die alternative Möglichkeit, den Autorisierungsheader nur für die zulässige Domäne festzulegen, wie im folgenden Beispiel. Platzieren Sie die folgende Funktion in jeder Datei, die bei jeder Ausführung der React-Anwendung ausgeführt wird, z. B. in der Routendatei.

export default () => {
    axios.interceptors.request.use(function (requestConfig) {
        if (requestConfig.url.indexOf(<ALLOWED_DOMAIN>) > -1) {
            const token = localStorage.token;
            requestConfig.headers['Authorization'] = `Bearer ${token}`;
        }

        return requestConfig;
    }, function (error) {
        return Promise.reject(error);
    });

}

0

Versuchen Sie, eine neue Instanz zu erstellen, wie ich es unten getan habe

var common_axios = axios.create({
    baseURL: 'https://sample.com'
});

// Set default headers to common_axios ( as Instance )
common_axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// Check your Header
console.log(common_axios.defaults.headers);

Wie man es benutzt

common_axios.get(url).......
common_axios.post(url).......

0
export const authHandler = (config) => {
  const authRegex = /^\/apiregex/;

  if (!authRegex.test(config.url)) {
    return store.fetchToken().then((token) => {
      Object.assign(config.headers.common, { Authorization: `Bearer ${token}` });
      return Promise.resolve(config);
    });
  }
  return Promise.resolve(config);
};

axios.interceptors.request.use(authHandler);

Beim Versuch, etwas Ähnliches zu implementieren, bin ich auf einige Fallstricke gestoßen, und basierend auf diesen Antworten habe ich mir das ausgedacht. Die Probleme, die ich hatte, waren:

  1. Wenn Sie Axios für die Anforderung verwenden, ein Token in Ihrem Geschäft abzurufen, müssen Sie den Pfad ermitteln, bevor Sie den Header hinzufügen. Wenn Sie dies nicht tun, wird versucht, den Header auch zu diesem Aufruf hinzuzufügen und in ein Problem mit der Kreisbahn zu geraten. Die Umkehrung des Hinzufügens von Regex zur Erkennung der anderen Anrufe würde ebenfalls funktionieren
  2. Wenn das Geschäft ein Versprechen zurückgibt, müssen Sie den Aufruf an das Geschäft zurückgeben, um das Versprechen in der authHandler-Funktion aufzulösen. Die Async / Await-Funktionalität würde dies einfacher / offensichtlicher machen
  3. Wenn der Aufruf des Authentifizierungstokens fehlschlägt oder der Aufruf zum Abrufen des Tokens ist, möchten Sie dennoch ein Versprechen mit der Konfiguration auflösen
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.