Lampirkan header Otorisasi untuk semua permintaan axios

130

Saya memiliki aplikasi react / redux yang mengambil token dari server api. Setelah pengguna mengautentikasi, saya ingin membuat semua permintaan axios memiliki token itu sebagai header Otorisasi tanpa harus melampirkannya secara manual ke setiap permintaan dalam tindakan. Saya cukup baru untuk bereaksi / redux dan tidak yakin dengan pendekatan terbaik dan saya tidak menemukan kualitas apa pun di Google.

Berikut adalah pengaturan redux saya:

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

Token saya disimpan di toko redux di bawah state.session.token.

Saya agak bingung bagaimana melanjutkan. Saya telah mencoba membuat contoh axios dalam file di direktori root saya dan memperbarui / impor itu alih-alih dari node_modules tetapi tidak melampirkan tajuk ketika keadaan berubah. Setiap umpan balik / ide sangat dihargai, terima kasih.

orang barat
sumber
Di mana Anda menyimpan token otorisasi setelah token diterima dari server? penyimpanan lokal?
Hardik Modha
dalam sesi toko
redux. token

Jawaban:

203

Ada banyak cara untuk mencapai ini. Di sini, saya telah menjelaskan dua pendekatan yang paling umum.

1. Anda dapat menggunakan interseptor axios untuk mencegat permintaan apa pun dan menambahkan header otorisasi.

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    const token = store.getState().session.token;
    config.headers.Authorization =  token;

    return config;
});

2. Dari dokumentasi dari axiosAnda dapat melihat ada mekanisme yang tersedia yang memungkinkan Anda untuk sundulan set default yang akan dikirim dengan setiap permintaan yang Anda buat.

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

Jadi dalam kasus Anda:

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

Jika mau, Anda dapat membuat fungsi yang dapat dijalankan sendiri yang akan menyetel header otorisasi itu sendiri saat token ada di toko.

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

Sekarang Anda tidak perlu lagi melampirkan token secara manual ke setiap permintaan. Anda dapat menempatkan fungsi di atas dalam file yang dijamin akan dijalankan setiap saat ( misal: File yang berisi rute).

Semoga membantu :)

Hardik Modha
sumber
1
sudah menggunakan redux-persist tetapi akan melihat middleware untuk memasang token di header, terima kasih!
awwester
1
@awwester Anda tidak perlu middleware untuk memasang token di header. Melampirkan token di header axios.defaults.header.common[Auth_Token] = tokensesederhana itu.
Hardik Modha
4
@HardikModha Saya ingin tahu bagaimana orang dapat melakukan ini dengan Fetch API.
Rowland
@Rowland Saya percaya, Anda harus menulis API pembungkus atas pengambilan untuk mencapai hal yang sama. Jawaban rinci atas pertanyaan tersebut berada di luar cakupan pertanyaan yang diajukan oleh OP. Anda dapat mengajukan pertanyaan lain :)
Hardik Modha
2
Hai @Hikodha. Jika saya menggunakan header default untuk set token ketika saya ingin memperbarui token, itu tidak dapat diatur lagi ke dalam header. Apakah itu benar? Jadi saya harus menggunakan pencegat.
pengembang pemula
50

Jika Anda menggunakan versi "axios": "^ 0.17.1", Anda dapat melakukan seperti ini:

Buat contoh aksios:

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

Kemudian untuk permintaan apa pun, token akan dipilih dari localStorage dan akan ditambahkan ke header permintaan.

Saya menggunakan contoh yang sama di seluruh aplikasi dengan kode ini:

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

Semoga berhasil.

llioor
sumber
@ NguyễnPhúc Dengan senang hati, intinya adalah menggunakan "interseptor" dari aksios
llioor
Ini adalah jawaban terbaik ... untuk menginisialisasi token pada interseptor untuk setiap permintaan! . Terima kasih
james ace
45

Solusi terbaik bagi saya adalah membuat layanan klien yang akan Anda buat dengan token Anda untuk digunakan sebagai pembungkus 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);

Di klien ini, Anda juga dapat mengambil token dari localStorage / cookie, seperti yang Anda inginkan.

Kmaschta
sumber
1
Bagaimana jika Anda ingin membuat request.get () dengan header "application-type". Dengan pendekatan Anda, header dari defaultOptions akan ditimpa oleh header dari permintaan. Aku benar? Terima kasih.
nipuro
9

Demikian pula, kami memiliki fungsi untuk mengatur atau menghapus token dari panggilan seperti ini:

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

Kami selalu membersihkan token yang ada saat inisialisasi, lalu menetapkan yang diterima.

elQueFaltaba
sumber
5

Jika Anda ingin memanggil rute api lain di masa mendatang dan menyimpan token Anda di toko, coba gunakan middleware redux .

Middleware dapat mendengarkan tindakan api dan mengirimkan permintaan api melalui axios yang sesuai.

Berikut adalah contoh yang sangat mendasar:

tindakan / 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);
};
Paul. B
sumber
3

Terkadang Anda mendapatkan kasus di mana beberapa permintaan yang dibuat dengan aksios diarahkan ke titik akhir yang tidak menerima header otorisasi. Dengan demikian, cara alternatif untuk mengatur header otorisasi hanya pada domain yang diizinkan adalah seperti pada contoh di bawah ini. Tempatkan fungsi berikut di file mana pun yang dijalankan setiap kali aplikasi React berjalan seperti di file routes.

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

}
Karolis Ramanauskas
sumber
0

Coba buat contoh baru seperti yang saya lakukan di bawah ini

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

Bagaimana cara menggunakannya

common_axios.get(url).......
common_axios.post(url).......
ugali lembut
sumber
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);

Bertemu beberapa masalah ketika mencoba menerapkan sesuatu yang serupa dan berdasarkan jawaban ini, inilah yang saya dapatkan. Masalah yang saya alami adalah:

  1. Jika menggunakan axios untuk permintaan mendapatkan token di toko Anda, Anda perlu mendeteksi jalur sebelum menambahkan header. Jika tidak, itu akan mencoba menambahkan header ke panggilan itu juga dan masuk ke masalah jalur melingkar. Kebalikan dari menambahkan regex untuk mendeteksi panggilan lain juga akan berfungsi
  2. Jika store mengembalikan promise, Anda perlu mengembalikan panggilan ke store untuk menyelesaikan promise dalam fungsi authHandler. Fungsionalitas Async / Await akan membuat ini lebih mudah / lebih jelas
  3. Jika panggilan untuk token autentikasi gagal atau panggilan untuk mendapatkan token, Anda masih ingin menyelesaikan janji dengan konfigurasi
Bhetzie
sumber
0

Intinya adalah menyetel token pada interseptor untuk setiap permintaan

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;
});
james ace
sumber