Приєднайте заголовок авторизації для всіх запитів axios


130

У мене є програма react / redux, яка отримує маркер з сервера api. Після автентифікації користувача я хотів би зробити всі запити axios таким маркерів як заголовок авторизації, не вручну додаючи його до кожного запиту в дії. Я досить новий, хто реагує / редукує, і не впевнений у найкращому підході, і не знаходжу жодних хітів якості в Google.

Ось моя настройка редукції:

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

Мій маркер зберігається в редукційному магазині під state.session.token.

Я трохи розгублений, як діяти далі. Я намагався зробити екземпляр axios у файлі в моєму кореневому каталозі та оновити / імпортувати це замість node_modules, але він не приєднує заголовок, коли стан змінюється. Будь-які відгуки / ідеї дуже вдячні, дякую.


Де ви зберігаєте маркер авторизації після отримання маркера від сервера? місцеві магазини?
Hardik Modha

в магазині
редукційних

Відповіді:


202

Існує кілька способів досягти цього. Тут я пояснив два найбільш поширені підходи.

1. Ви можете використовувати перехоплювачі axios для перехоплення будь-яких запитів та додавання заголовків авторизації.

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

    return config;
});

2. З документації по axiosви можете побачити , є доступний механізм , який дозволяє встановити заголовок по замовчуванням , який буде відправлений з кожним запитом ви робите.

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

Тож у вашому випадку:

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

Якщо ви хочете, ви можете створити самостійно виконувану функцію, яка буде встановлювати сам заголовок авторизації, коли маркер присутній у магазині.

(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'];
         */
     }
})();

Тепер вам більше не потрібно вручну додавати маркер до кожного запиту. Ви можете розмістити вищевказану функцію у файлі, який гарантовано виконується кожного разу ( наприклад: Файл, який містить маршрути).

Сподіваюся, це допомагає :)


1
вже використовуючи redux-persist, але поглянемо на проміжне програмне забезпечення, щоб прикріпити маркер у заголовку, дякую!
австер

1
@awwester Вам не потрібно проміжне програмне забезпечення, щоб прикріпити маркер у заголовку. Прикріплення маркера до заголовка так axios.defaults.header.common[Auth_Token] = tokenсамо просто.
Hardik Modha

4
@HardikModha Мені цікаво, як можна зробити це за допомогою API Fetch.
Роуленд

@Rowland Я вважаю, що вам потрібно буде написати обгортку над API для отримання. Детальна відповідь на це питання виходить за межі питання, яке задає ОП. Ви можете задати ще одне питання :)
Hardik Modha

2
Привіт @HardikModha. Якщо я використовую заголовки за замовчуванням для встановленого маркера, коли я хочу оновити маркер, він не може бути встановлений знову в заголовку. це правильно? Тому я повинен використовувати перехоплювачі.
beginerdeveloper

50

Якщо ви використовуєте "axios": "^ 0.17.1" версія, ви можете зробити так:

Створіть екземпляр axios:

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

Тоді для будь-якого запиту маркер буде обраний з localStorage і буде доданий до заголовків запиту.

Я використовую той самий примірник у всій програмі з цим кодом:

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

Удачі.


@ NguyễnPhúc Із задоволенням вся справа в тому, щоб використовувати «перехоплювачі» аксіосів
llioor

Це найкраща відповідь ... ініціалізувати маркер на перехоплювачах для кожного запиту! . Спасибі
Джеймс туз

45

Найкраще для мене рішення - створити службу для клієнтів, яку ви будете створювати своїм маркером, використовуючи його для завершення 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);

У цьому клієнті ви також можете отримати маркер з localStorage / cookie, як вам захочеться.


1
Що робити, якщо ви хочете створити request.get () із заголовками "типу програми". З вашим підходом заголовки з defaultOptions будуть замінені заголовками із запиту. Я правий? Дякую.
nipuro

9

Аналогічно, у нас є функція встановлення або видалення маркера з таких викликів:

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

Ми завжди очищаємо наявний маркер при ініціалізації, а потім встановлюємо отриманий.


5

Якщо ви хочете зателефонувати до інших api-маршрутів і зберегти маркер у магазині, то спробуйте скористатись програмним забезпеченням redux .

Програмне забезпечення може прослуховувати дії api та відповідно відправляти запити api через axios.

Ось дуже основний приклад:

дії / 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'
  };
}

посередництво / 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

Іноді трапляється випадок, коли деякі запити, зроблені аксіосами, вказують на кінцеві точки, які не приймають заголовки авторизації. Таким чином, альтернативний спосіб встановлення заголовка авторизації лише на дозволений домен, як у наведеному нижче прикладі. Розмістіть наступну функцію у будь-якому файлі, який виконується кожного разу, коли програма React запускається, наприклад у файлі маршрутів.

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

Спробуйте зробити новий екземпляр, як я зробив нижче

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

Як ним користуватися

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

Натрапивши на якісь проблеми, намагаючись реалізувати щось подібне, і на основі цих відповідей я ось що придумав. Проблеми, які я відчував:

  1. Якщо ви використовуєте axios для запиту, щоб отримати маркер у вашому магазині, вам потрібно визначити шлях перед додаванням заголовка. Якщо ви цього не зробите, він також спробує додати заголовок до цього виклику і потрапить у проблему кругового шляху. Зворотне додавання регулярного вираження для виявлення інших дзвінків також буде працювати
  2. Якщо магазин повертає обіцянку, вам потрібно повернути виклик у магазин, щоб вирішити обіцянку у функції authHandler. Функція Async / Await зробить це простішим / очевидним
  3. Якщо виклик для маркера автентичності не вдається або це виклик отримати маркер, ви все одно хочете вирішити обіцянку з конфігурацією

0

Суть у тому, щоб встановити маркер на перехоплювачах для кожного запиту

import axios from "axios";
    
const httpClient = axios.create({
    baseURL: "http://youradress",
    // baseURL: process.env.APP_API_BASE_URL,
});

httpClient.interceptors.request.use(function (config) {
    const token = localStorage.getItem('token');
    config.headers.Authorization =  token ? `Bearer ${token}` : '';
    return config;
});
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.