为所有 axios 请求附加授权头

IT技术 reactjs redux axios
2021-03-29 03:44:28

我有一个从 api 服务器获取令牌的 react/redux 应用程序。在用户进行身份验证后,我想让所有 axios 请求都将该令牌作为 Authorization 标头,而不必手动将其附加到操作中的每个请求。我对 react/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;
  }
}

我的令牌存储在state.session.token.

我对如何进行有点迷茫。我已经尝试在我的根目录中的文件中创建一个axios 实例并更新/导入它而不是从 node_modules 中,但是当状态改变时它没有附加标题。非常感谢任何反馈/想法,谢谢。

6个回答

有多种方法可以实现这一点。在这里,我解释了两种最常见的方法。

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

现在您不再需要手动将令牌附加到每个请求。您可以将上述函数放在保证每次都执行的文件中例如:包含路由的文件)。

希望能帮助到你 :)

一个小问题:如果您遵循第二种方法,则必须分别为应用程序中的每个 Axios 实例设置默认标头。这花了我一段时间才弄明白。
2021-05-23 03:44:28
@HardikModha 我很好奇如何使用 Fetch API 做到这一点。
2021-06-01 03:44:28
嗨@HardikModha。如果我想更新令牌时使用设置令牌的默认标头,则无法再次将其设置到标头中。这是正确的吗?所以我必须使用拦截器。
2021-06-06 03:44:28
@awwester 您不需要中间件来在标头中附加令牌。在标头中附加令牌就是axios.defaults.header.common[Auth_Token] = token这么简单。
2021-06-07 03:44:28
已经在使用 redux-persist 但会看看中间件以在标头中附加令牌,谢谢!
2021-06-15 03:44:28

创建 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 的“拦截器”
2021-06-12 03:44:28
这是最好的答案......为每个请求在拦截器上初始化令牌!. 谢谢
2021-06-18 03:44:28

对我来说最好的解决方案是创建一个客户端服务,您将使用您的令牌实例化它并使用它来包装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 中检索令牌。

如果您想让 request.get() 带有“application-type”标头怎么办。使用您的方法,来自 defaultOptions 的标头将被来自请求的标头覆盖。我是正确的?谢谢你。
2021-06-12 03:44:28

同样,我们有一个函数来设置或删除这样的调用中的令牌:

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

我们总是在初始化时清理现有的令牌,然后建立接收到的令牌。

重点是为每个请求在拦截器上设置令牌

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