我有一个react/redux应用程序,从api服务器获取一个令牌。在用户进行身份验证之后,我希望所有axios请求都具有该令牌作为授权标头,而不必手动将其附加到操作中的每个请求。我是相当新的反应/redux,我不确定最好的方法,我没有找到任何高质量的谷歌。
这是我的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 store下的state.session.token。
我有点不知道该怎么做。我尝试在根目录的文件中创建一个axios实例,并更新/导入该实例,而不是从node_modules中更新/导入,但当状态发生变化时,它没有附加头文件。任何反馈/想法都非常感谢,谢谢。
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);
在尝试实现类似的东西时遇到了一些陷阱,基于这些答案,这是我想出的。我遇到的问题是:
If using axios for the request to get a token in your store, you need to detect the path before adding the header. If you don't, it will try to add the header to that call as well and get into a circular path issue. The inverse of adding regex to detect the other calls would also work
If the store is returning a promise, you need to return the call to the store to resolve the promise in the authHandler function. Async/Await functionality would make this easier/more obvious
If the call for the auth token fails or is the call to get the token, you still want to resolve a promise with the config
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);
在尝试实现类似的东西时遇到了一些陷阱,基于这些答案,这是我想出的。我遇到的问题是:
If using axios for the request to get a token in your store, you need to detect the path before adding the header. If you don't, it will try to add the header to that call as well and get into a circular path issue. The inverse of adding regex to detect the other calls would also work
If the store is returning a promise, you need to return the call to the store to resolve the promise in the authHandler function. Async/Await functionality would make this easier/more obvious
If the call for the auth token fails or is the call to get the token, you still want to resolve a promise with the config
对我来说,最好的解决方案是创建一个客户端服务,您将实例化您的令牌,并使用它来包装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检索令牌。