모든 axios 요청에 대한 인증 헤더 첨부


130

API 서버에서 토큰을 가져 오는 react / redux 애플리케이션이 있습니다. 사용자가 인증 한 후 모든 axios 요청이 작업의 모든 요청에 ​​수동으로 첨부 할 필요없이 해당 토큰을 Authorization 헤더로 갖도록 만들고 싶습니다. 나는 반응 / redux를 처음 접했으며 최선의 접근 방식을 확신하지 못하며 Google에서 품질 히트를 찾지 못했습니다.

내 redux 설정은 다음과 같습니다.

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

내 토큰은 아래의 redux 저장소에 저장됩니다 state.session.token.

진행 방법에 대해 조금 잃었습니다. 루트 디렉토리의 파일에 axios 인스턴스 를 만들고 node_modules 대신 업데이트 / 가져 오기를 시도했지만 상태가 변경 될 때 헤더를 첨부하지 않습니다. 모든 피드백 / 아이디어는 대단히 감사합니다.


서버에서 토큰을받은 후 인증 토큰을 어디에 저장합니까? localStorage?
Hardik Modha

redux 스토어 session.token
awwester

답변:


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를 사용하고 있지만 헤더에 토큰을 첨부하기 위해 미들웨어를 살펴볼 것입니다. 감사합니다!
awwester

1
@awwester 헤더에 토큰을 첨부하기 위해 미들웨어가 필요하지 않습니다. 헤더에 토큰을 첨부하는 것은 axios.defaults.header.common[Auth_Token] = token간단합니다.
Hardik Modha

4
@HardikModha Fetch API로이 작업을 수행 할 수있는 방법이 궁금합니다.
Rowland

@Rowland 나는 같은 것을 달성하기 위해 fetch API에 대한 래퍼를 작성해야한다고 믿습니다. 이 질문에 대한 자세한 답변은 OP가 묻는 질문의 범위를 벗어납니다. 당신은 다른 질문 : 요청할 수 있습니다
Hardik Modha

2
안녕하세요 @HardikModha. 토큰을 갱신 할 때 설정된 토큰에 기본 헤더를 사용하면 헤더에 다시 설정할 수 없습니다. 맞습니까? 그래서 인터셉터를 사용해야합니다.
초보 개발자

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 기쁨으로 요점은
axios

이것이 가장 좋은 대답입니다 ... 각 요청에 대해 인터셉터에서 토큰을 초기화하는 것입니다! . 감사합니다
james ace

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 / 쿠키에서 토큰을 검색 할 수도 있습니다.


1
"application-type"헤더로 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 작업을 수신하고 그에 따라 axios를 통해 api 요청을 전달할 수 있습니다.

다음은 매우 기본적인 예입니다.

actions / 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

때때로 axios로 이루어진 일부 요청이 인증 헤더를 허용하지 않는 엔드 포인트를 가리키는 경우가 있습니다. 따라서 허용 된 도메인에서만 인증 헤더를 설정하는 다른 방법은 아래 예와 같습니다. Route 파일과 같이 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. 스토어가 promise를 반환하는 경우 authHandler 함수에서 promise를 해결하기 위해 스토어에 호출을 반환해야합니다. 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;
});
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.