แนบส่วนหัวการอนุญาตสำหรับคำขอ axios ทั้งหมด


133

ฉันมีแอปพลิเคชัน react / redux ที่ดึงโทเค็นจากเซิร์ฟเวอร์ api หลังจากผู้ใช้ตรวจสอบสิทธิ์แล้วฉันต้องการให้คำขอ axios ทั้งหมดมีโทเค็นนั้นเป็นส่วนหัวการอนุญาตโดยไม่ต้องแนบด้วยตนเองกับทุกคำขอในการดำเนินการ ฉันค่อนข้างใหม่ในการตอบสนอง / 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 แต่ไม่ได้แนบส่วนหัวเมื่อสถานะเปลี่ยนไป ข้อเสนอแนะ / ความคิดใด ๆ ที่ชื่นชมมากขอบคุณ


คุณเก็บโทเค็นการอนุญาตไว้ที่ไหนหลังจากได้รับโทเค็นจากเซิร์ฟเวอร์แล้ว localStorage?
Hardik Modha

ในร้านค้า redux session.token
เมื่อ

คำตอบ:


206

มีหลายวิธีในการบรรลุเป้าหมายนี้ ที่นี่ฉันได้อธิบายสองแนวทางที่พบบ่อยที่สุด

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

ตอนนี้คุณไม่จำเป็นต้องแนบโทเค็นด้วยตนเองในทุกคำขออีกต่อไป คุณสามารถวางฟังก์ชันข้างต้นลงในไฟล์ซึ่งรับประกันว่าจะดำเนินการทุกครั้ง ( เช่นไฟล์ที่มีเส้นทาง)

หวังว่าจะช่วยได้ :)


1
ใช้ redux-persist อยู่แล้ว แต่จะดูมิดเดิลแวร์เพื่อแนบโทเค็นในส่วนหัวขอบคุณ!

1
@awwester คุณไม่จำเป็นต้องใช้มิดเดิลแวร์เพื่อแนบโทเค็นในส่วนหัว การแนบโทเค็นในส่วนหัวaxios.defaults.header.common[Auth_Token] = tokenทำได้ง่ายเพียงแค่นั้น
Hardik Modha

4
@HardikModha ฉันอยากรู้ว่าเราจะทำสิ่งนี้กับ Fetch API ได้อย่างไร
Rowland

@Rowland ฉันเชื่อว่าคุณจะต้องเขียน wrapper บน fetch API เพื่อให้ได้สิ่งเดียวกัน คำตอบโดยละเอียดสำหรับคำถามนั้นอยู่นอกขอบเขตของคำถามที่ OP ถาม คุณสามารถถามคำถามอื่นได้ :)
Hardik Modha

2
สวัสดี @HardikModha หากฉันใช้ส่วนหัวเริ่มต้นสำหรับโทเค็นที่ตั้งไว้เมื่อฉันต้องการต่ออายุโทเค็นจะไม่สามารถตั้งค่าลงในส่วนหัวได้อีก ถูกต้องหรือไม่ ฉันจึงต้องใช้เครื่องสกัดกั้น
beginerdeveloper

51

หากคุณใช้เวอร์ชัน "axios": "^ 0.17.1" คุณสามารถทำได้ดังนี้:

สร้างอินสแตนซ์ของ 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ด้วยความยินดีประเด็นทั้งหมดคือการใช้ "interceptors" ของ axios
llioor

1
นี่คือคำตอบที่ดีที่สุด ... ในการเริ่มต้นโทเค็นบนตัวสกัดกั้นสำหรับแต่ละคำขอ! . ขอบคุณ
james ace

45

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 / คุกกี้ได้ตามที่คุณต้องการ


1
จะเกิดอะไรขึ้นถ้าคุณต้องการสร้าง request.get () ด้วยส่วนหัว "application-type" ด้วยแนวทางของคุณส่วนหัวจาก defaultOptions จะถูกแทนที่โดยส่วนหัวจากคำขอ ฉันถูก? ขอบคุณ.
nipuro

9

ในทำนองเดียวกันเรามีฟังก์ชั่นในการตั้งค่าหรือลบโทเค็นจากการโทรเช่นนี้:

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

เราทำความสะอาดโทเค็นที่มีอยู่เมื่อเริ่มต้นเสมอจากนั้นสร้างโทเค็นที่ได้รับ


5

หากคุณต้องการที่จะเรียกเส้นทาง API อื่น ๆ ในอนาคตและให้โทเค็นของคุณในการจัดเก็บแล้วลองใช้ตัวกลาง Redux

มิดเดิลแวร์สามารถรับฟังการดำเนินการ api และส่งคำขอ api ผ่าน axios ได้

นี่คือตัวอย่างพื้นฐาน:

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

มิดเดิลแวร์ / 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);
};

3

บางครั้งคุณจะได้รับกรณีที่คำขอบางส่วนที่ทำด้วยแกนถูกชี้ไปที่ปลายทางที่ไม่ยอมรับส่วนหัวการให้สิทธิ์ ดังนั้นวิธีอื่นในการตั้งค่าส่วนหัวการอนุญาตเฉพาะในโดเมนที่อนุญาตมีดังตัวอย่างด้านล่าง วางฟังก์ชันต่อไปนี้ในไฟล์ใด ๆ ที่เรียกใช้งานทุกครั้งที่แอปพลิเคชัน React ทำงานเช่นในไฟล์เส้นทาง

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

}

0

ลองสร้างอินสแตนซ์ใหม่เหมือนที่ฉันทำด้านล่าง

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

วิธีการใช้งาน

common_axios.get(url).......
common_axios.post(url).......

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

พบกับ gotchas บางอย่างเมื่อพยายามใช้สิ่งที่คล้ายกันและจากคำตอบเหล่านี้นี่คือสิ่งที่ฉันคิดขึ้นมา ปัญหาที่ฉันพบคือ:

  1. หากใช้ axios เพื่อขอโทเค็นในร้านค้าของคุณคุณจะต้องตรวจหาเส้นทางก่อนที่จะเพิ่มส่วนหัว หากคุณไม่ทำเช่นนั้นจะพยายามเพิ่มส่วนหัวให้กับการโทรนั้นด้วยและทำให้เกิดปัญหาเส้นทางวงกลม การผกผันของการเพิ่ม regex เพื่อตรวจจับการโทรอื่น ๆ ก็ใช้ได้เช่นกัน
  2. หากร้านค้าส่งคืนคำสัญญาคุณจะต้องโทรกลับไปที่ร้านค้าเพื่อแก้ไขคำสัญญาในฟังก์ชัน authHandler ฟังก์ชัน Async / Await จะทำให้สิ่งนี้ง่ายขึ้น / ชัดเจนมากขึ้น
  3. หากการเรียกโทเค็นการตรวจสอบสิทธิ์ล้มเหลวหรือเป็นการเรียกเพื่อรับโทเค็นคุณยังคงต้องการแก้ไขสัญญาด้วยการกำหนดค่า

0

ประเด็นคือการตั้งค่าโทเค็นบนตัวสกัดกั้นสำหรับแต่ละคำขอ

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;
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.