2017-03-27 32 views
8

Ich habe eine Reaktion/Redux-Anwendung, die ein Token von einem API-Server holt. Nachdem der Benutzer sich authentifiziert hat, möchte ich veranlassen, dass alle Axios-Anfragen dieses Token als Autorisierungsheader haben, ohne es manuell an jede Anfrage in der Aktion anhängen zu müssen. Ich bin ziemlich neu zu reagieren/redux und bin mir nicht sicher über den besten Ansatz und finde keine Qualitätstreffer auf Google.Anfügen Authorization Header für alle Axios Anfragen

Hier ist meine redux Setup:

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

Meine Token in redux Speichern unter state.session.token gespeichert werden.

Ich bin ein bisschen verloren, wie es weiter geht. Ich habe versucht, eine axios instance in einer Datei in meinem Stammverzeichnis und aktualisieren/importieren, dass anstelle von node_modules, aber es fügt nicht die Kopfzeile, wenn der Zustand ändert. Irgendwelche Rückmeldungen/Ideen werden sehr geschätzt, danke.

+0

Wo speichern Sie das Autorisierungstoken, nachdem das Token vom Server empfangen wurde? lokaler Speicher? –

+0

in redux store session.token – awwester

Antwort

5

Aus der documentation von axios können Sie sehen, es gibt einen Mechanismus zur Verfügung, mit dem Sie Standard-Header festlegen können, die mit jeder Anfrage gesendet werden, die Sie machen.

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

So in Ihrem Fall

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

Wenn Sie möchten, können Sie eine selbstausführbaren Funktion erstellen, die sich Autorisierungsheader gesetzt wird, wenn das Token im Speicher vorhanden ist.

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

Jetzt müssen Sie Token nicht mehr manuell an jede Anfrage anhängen. Sie können die obige Funktion in die Datei einfügen, die garantiert jedes Mal ausgeführt wird. e.g. Datei, die die Routen enthält.

Hoffe, es hilft :)

+0

bereits redux-persist verwenden, aber werfen Sie einen Blick auf Middleware, um das Token im Header zu befestigen, danke! – awwester

+0

@awwester Sie benötigen keine Middleware, um das Token in der Kopfzeile anzuhängen. Das Anhängen des Tokens im Header ist 'axios.defaults.header.common [Auth_Token] = token' so einfach. –

+0

@HardikModha Ich bin gespannt wie man das mit Fetch API machen könnte. – Rowland

11

Die beste Lösung für mich ist, einen Client-Service zu erstellen, den Sie mit Ihrem Token instanziieren und es verwenden, um axios zu wickeln.

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

In diesem Client können Sie das Token auch aus dem localStorage/cookie abrufen, wie Sie möchten.

+1

Awesome Ansatz @kmascha – Rowland

0

Wenn Sie andere api Routen in Zukunft anrufen möchten, und halten Sie Ihre Token in den Laden dann using redux middleware versuchen.

Die Middleware könnte auf die api-Aktion warten und API-Anfragen über Axios entsprechend versenden.

Dies ist ein sehr einfaches Beispiel:

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

Ebenso haben wir eine Funktion zu setzen oder das Token aus Anrufen wie diese zu löschen:

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

Wir reinigen immer das bestehende Token bei der Initialisierung, dann das empfangene eines etablieren.

2

Wenn Sie "Axios": "^ 0.17.1" -Version können Sie wie folgt tun:

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

dann für jede Anforderung das Token wählen sein aus localStorage und wird den Anforderungsheadern hinzugefügt.

Ich bin mit dem gleichen Instanz der ganzen App mit diesem Code:

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

Viel Glück.

Verwandte Themen