vue.js/vue.js 2

120. Request 요청에 Token 넣어서 API 가져오기 | 액시오스 인터셉터 | 인터셉터 모듈화

DEV-Front 2023. 1. 24. 22:16
반응형

public 폴더의 index.html이 애플리케이션의 가장 첫번째 진입점이다.

- 여기에 폰트, 아이콘 추가 하는것


Token

- 사용자가 인증 되었을때만 발급되는것


로그인한 사용자의 토큰을 넣어서 API에 넘길거다. 토큰값을 어딘가에 저장하고 API 호출할때마다 사용할것

 

1. axios.create에 headers 추가하기

- Authorization 속성에 test1234 라고 쓴 후 API 요청을 실행했을때 네트워크 패널에서 Authorization에 test1234가 있는걸 확인 할 수 있다.

import axios from 'axios';

// axios.create 할때 주입한 속성은 인스턴스로 데이터 요청 할때마다 무조건 이 속성들이 정의된 상태로 수행된다.
const instance = axios.create({
  baseURL: process.env.VUE_APP_API_URL,
  // HTTP 헤더에 있는 속성
  headers: {
    Authorization: 'test1234',
  },
});

function registerUser(userData) {
  return instance.post('signup', userData);
}

function loginUser(userData) {
  return instance.post('login', userData);
}

export { registerUser, loginUser };


2. store에 Token 추가

import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    username: '',
    token: '', //token
  },
  getters: {
    isLogin(state) {
      return state.username !== '';
    },
  },
  mutations: {
    setUsername(state, username) {
      state.username = username;
    },
    clearUsername(state) {
      state.username = '';
    },
    setToken(state, token) {
      state.token = token; //token
    },
  },
});

3. loginForm 로그인 후 Token 값 store에 저장

<template>
  <div class="contents">
    <div class="form-wrapper form-wrapper-sm">
      <form @submit.prevent="submitForm" class="form">
        <div>
          <label for="username">id:</label>
          <input id="username" type="text" v-model="username" />
          <p class="validation-text">
            <span class="warning" v-if="!isUsernameValid && username">
              Please enter an email address
            </span>
          </p>
        </div>
        <div>
          <label for="password">pw:</label>
          <input id="password" type="text" v-model="password" />
        </div>
        <button
          :disabled="!isUsernameValid || !password"
          type="submit"
          class="btn"
        >
          로그인
        </button>
      </form>
      <p class="log">{{ logMessage }}</p>
    </div>
  </div>
</template>

<script>
import { loginUser } from '@/api/index';
import { validateEmail } from '@/utils/validation';

export default {
  data() {
    return {
      // form values
      username: '',
      password: '',
      // log
      logMessage: '',
    };
  },
  computed: {
    isUsernameValid() {
      return validateEmail(this.username);
    },
  },
  methods: {
    async submitForm() {
      try {
        // 비즈니스 로직
        const userData = {
          username: this.username,
          password: this.password,
        };
        const { data } = await loginUser(userData);
        console.log(data.token);
        this.$store.commit('setToken', data.token); //token
        this.$store.commit('setUsername', data.user.username);
        this.$router.push('/main');
      } catch (error) {
        // 에러 핸들링할 코드
        console.log(error.response.data);
        this.logMessage = error.response.data;
      } finally {
        this.initForm();
      }
    },
    initForm() {
      this.username = '';
      this.password = '';
    },
  },
};
</script>

<style>
.btn {
  color: white;
}
</style>

4. api 폴더 index.js에 Authorization: store.state.token

import axios from 'axios';
import store from '@/store/index'; //import 꼭 해줘야함

// axios.create 할때 주입한 속성은 인스턴스로 데이터 요청 할때마다 무조건 이 속성들이 정의된 상태로 수행된다.
const instance = axios.create({
  baseURL: process.env.VUE_APP_API_URL,
  // HTTP 헤더에 있는 속성
  headers: {
    // 토큰을 여기에 실을것
    Authorization: store.state.token,
  },
});

function registerUser(userData) {
  return instance.post('signup', userData);
}

function loginUser(userData) {
  return instance.post('login', userData);
}

export { registerUser, loginUser };


5. Interceptors 사용 (그냥 쓰면 API 호출 하기전에 Request에 Token 값 보내는게 됨)

- Interceptors 는 서버 요청, 응답을 처리하기 전에 추가 로직을 넣을수 있는것

- 말 그대로 가로채기

https://github.com/axios/axios#interceptors

 

GitHub - axios/axios: Promise based HTTP client for the browser and node.js

Promise based HTTP client for the browser and node.js - GitHub - axios/axios: Promise based HTTP client for the browser and node.js

github.com

- api 폴더에 common 폴더 추가, interceptors.js 파일 추가

- index.js 파일에 늘어놓으면 뭐하는 컴포넌트인지 한눈에 보기 어려워짐으로 분리한것


6. interceptors.js 파일에 setInterceptors 함수 생성 (인터셉터의 모듈화)

// 무분별하게 늘어놓는것보단 함수로 묶기 + export 시키기 + instance 받아오기
export function setInterceptors(instance) {
  // aixos → instance 로 설정 변경
  // Add a request interceptor
  instance.interceptors.request.use(
    function(config) {
      // Do something before request is sent
      return config;
    },
    function(error) {
      // Do something with request error
      return Promise.reject(error);
    },
  );
  // aixos → instance 로 설정 변경
  // Add a response interceptor
  instance.interceptors.response.use(
    function(response) {
      // Any status code that lie within the range of 2xx cause this function to trigger
      // Do something with response data
      return response;
    },
    function(error) {
      // Any status codes that falls outside the range of 2xx cause this function to trigger
      // Do something with response error
      return Promise.reject(error);
    },
  );

  // aixos → instance 설정 다 하고 return
  return instance;
}

7. api폴더 index.js 파일에 createInstance 함수 생성 (인터셉터의 모듈화)

import axios from 'axios';
import store from '@/store/index';
// interceptors.js 에서 setInterceptors 함수 받아오기
import { setInterceptors } from './common/interceptors';

// createInstance 함수로 하나로 묶기.
// 이렇게 하면 이 함수의 결과는 instance를 셋업하고 interceptors를 설정하게됨
function createInstance() {
  // axios.create 할때 주입한 속성은 인스턴스로 데이터 요청 할때마다 무조건 이 속성들이 정의된 상태로 수행된다.
  const instance = axios.create({
    baseURL: process.env.VUE_APP_API_URL,
    // HTTP 헤더에 있는 속성
    headers: {
      // 토큰을 여기에 실을것
      Authorization: store.state.token,
    },
  });
  // setInterceptors 함수에 instance 보내기
  return setInterceptors(instance);
}

// createInstance함수 값 받아오기
const instance = createInstance();

function registerUser(userData) {
  return instance.post('signup', userData);
}

function loginUser(userData) {
  return instance.post('login', userData);
}

export { registerUser, loginUser };

8. 인터셉터에 Token 넣기 

- config.headers.Authorization = store.state.token;

- config를 console 로 확인해보면 headers가 있는걸 확인 할 수 있다.

- 여기에 Authorization 추가 후 token 값 넣기

 

이런식으로 매 API 요청마다 일일이 실어주는게 아니라 Authorization 속성, interceptors 라는 속성을 이용해서

매번 Store에 있는 state의 값을 들고와서 담아준단것을 확인 할 수 있다.

import store from '@/store/index';

// 무분별하게 늘어놓는것보단 함수로 묶기 + export 시키기 + instance 받아오기
export function setInterceptors(instance) {
  // aixos → instance 로 설정 변경
  // Add a request interceptor
  instance.interceptors.request.use(
    function(config) {
      // Do something before request is sent Request에 요청을 보내기 직전 코드

      // HTTP 헤더에 있는 속성 - headers
      config.headers.Authorization = store.state.token;
      return config;
    },
    function(error) {
      // Do something with request error
      // 보냈을때 에러가나면 처리
      return Promise.reject(error);
    },
  );
  // aixos → instance 로 설정 변경
  // Add a response interceptor
  instance.interceptors.response.use(
    function(response) {
      // Any status code that lie within the range of 2xx cause this function to trigger
      // Do something with response data
      return response;
    },
    function(error) {
      // Any status codes that falls outside the range of 2xx cause this function to trigger
      // Do something with response error
      return Promise.reject(error);
    },
  );

  // aixos → instance 설정 다 하고 return
  return instance;
}

완성

반응형