reactjs - react - Adjuntar encabezado de autorización para todas las solicitudes de axios
redux-axios-middleware (6)
A veces, aparece un caso en el que algunas de las solicitudes realizadas con axios apuntan a puntos finales que no aceptan encabezados de autorización. Por lo tanto, una forma alternativa de establecer el encabezado de autorización solo en el dominio permitido es como en el siguiente ejemplo. Coloque la siguiente función en cualquier archivo que se ejecute cada vez que se ejecute la aplicación React, como en el archivo de rutas.
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);
});
}
Tengo una aplicación react / redux que obtiene un token de un servidor api. Después de que el usuario se autentique, me gustaría hacer que todas las solicitudes de axios tengan ese token como un encabezado de Autorización sin tener que adjuntarlo manualmente a cada solicitud en la acción. Soy bastante nuevo en reaccionar / reducir y no estoy seguro del mejor enfoque y no encuentro resultados de calidad en Google.
Aquí está mi configuración 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;
}
}
Mi token se almacena en la tienda redux en
state.session.token
.
Estoy un poco perdido sobre cómo proceder. Intenté hacer una instancia de axios en un archivo en mi directorio raíz y actualizar / importar eso en lugar de hacerlo desde node_modules pero no adjunta el encabezado cuando cambia el estado. Cualquier comentario / ideas son muy apreciadas, gracias.
Del mismo modo, tenemos una función para configurar o eliminar el token de llamadas como esta:
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}`;
}
}
Siempre limpiamos el token existente en la inicialización, luego establecemos el token recibido.
Hay múltiples formas de lograr esto. Aquí, he explicado los dos enfoques más comunes.
1. Puede usar los interceptores axios para interceptar cualquier solicitud y agregar encabezados de autorización.
// Add a request interceptor
axios.interceptors.request.use(function (config) {
const token = store.getState().session.token;
config.headers.Authorization = token;
return config;
});
2. De la
documentation
de
axios
puede ver que hay un mecanismo disponible que le permite configurar el encabezado predeterminado que se enviará con cada solicitud que realice.
axios.defaults.headers.common[''Authorization''] = AUTH_TOKEN;
Entonces en tu caso:
axios.defaults.headers.common[''Authorization''] = store.getState().session.token;
Si lo desea, puede crear una función autoejecutable que establecerá el encabezado de autorización cuando el token esté presente en la tienda.
(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''];
*/
}
})();
Ahora ya no necesita adjuntar el token manualmente a cada solicitud. Puede colocar la función anterior en el archivo que se garantiza que se ejecutará cada vez ( por ejemplo: archivo que contiene las rutas).
Espero eso ayude :)
La mejor solución para mí es crear un servicio de cliente que pueda crear instancias con su token y usarlo para envolver
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);
En este cliente, también puede recuperar el token de localStorage / cookie, como lo desee.
Si desea llamar a otras rutas de API en el futuro y mantener su token en la tienda, intente usar el middleware redux .
El middleware podría escuchar la acción de una API y enviar las solicitudes de API a través de axios en consecuencia.
Aquí hay un ejemplo muy básico:
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);
};
Si usa la versión "axios": "^ 0.17.1" puede hacer lo siguiente:
Crear instancia de 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;
});
Luego, para cualquier solicitud, el token se seleccionará de localStorage y se agregará a los encabezados de solicitud.
Estoy usando la misma instancia en toda la aplicación con este código:
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();
Buena suerte.