0419 - 0425

0419 ~ 0423

중간고사 기간

0424

중간고사를 마무리 하고 다시 프로젝트를 이어서 진행하였다. api를 사용하는 영역을 모듈화 하고 인터셉터로 처리하였다.

인터셉터

// interceptors.js
import store from "@/store/index";

export function setInterceptors(axiosService) {
  axiosService.interceptors.request.use(
    function (config) {
      // 요청을 보내기 전에 어떤 처리를 할 수 있다.
      config.headers.Authorization = `Bearer ${store.state.member.token}`;
      console.log(config);
      return config;
    },
    function (error) {
      // 요청이 잘못되었을 때, 에러가 컴포넌트 단으로 오기 전에 어떤 처리를 할 수 있다.
      return Promise.reject(error);
    }
  );

  axiosService.interceptors.response.use(
    function (response) {
      // 요청을 보내고 나서 응답을 받기 전에 어떤 처리를 할 수 있다.
      console.log(response);
      return response;
    },
    function (error) {
      // 응답이 에러인 경우 미리 처리할 수 있다.
      return Promise.reject(error);
    }
  );

  return axiosService;
}
  • 인터셉터를 이용하면 HTTP 요청과 응답을 컴포넌트 단에서 처리하기 전에 추가 로직을 넣을 수 있다.
  • 요청하기 전에 헤더의 권한에 스토어에 저장된 토큰 값을 설정하였다.
  • 요청과 응답 모두 결과를 확인하기 위해 console.log로 찍어보았다.

모듈화

// index.js
import axios from "axios";
import { setInterceptors } from "./common/interceptors";

function createAxiosService() {
  return axios.create({
    baseURL: process.env.VUE_APP_API_URL,
  });
}

function createAxiosServiceWithAuth() {
  const axiosService = axios.create({
    baseURL: process.env.VUE_APP_API_URL,
  });

  return setInterceptors(axiosService);
}

export const axiosService = createAxiosService();
export const axiosServiceWithAuth = createAxiosServiceWithAuth();
  • 모듈화를 하기 위해 공통으로 설정할 index.js를 작성하였다.
  • axiosService는 기본 api 호출을 위한 것이고, axiosServiceWithAuth는 인터셉터를 거쳐서 토큰을 권한에 설정하여 로그인이 필요한 api를 호출하기 위해 구분한 것이다.
// member.js
import { axiosService } from "./index";

const register = data => {
  return axiosService.post("members/new", data);
};

const login = data => {
  return axiosService.post("members/login", data, { withCredentials: true });
};

export default { register, login };

// board.js
import { axiosServiceWithAuth } from "./index";

const getBoardList = data => {
  return axiosServiceWithAuth.get("boards/lists", data);
};

export default { getBoardList };
  • 위와 같이 index.js만 import하여 코드가 훨씬 간결해지고 깔끔해졌다.

0425

로그인, 로그아웃

vuex만 사용하면 새로고침 시 저장된 state가 초기화 되기 때문에 쿠키를 사용해서 기능을 구현하였다.

// utils/cookies.js
const getAuthFromCookie = () => {
  return document.cookie.replace(
    /(?:(?:^|.*;\s*)jwt\s*=\s*([^;]*).*$)|^.*$/,
    "$1"
  );
};

const getMemberNameFromCookie = () => {
  return document.cookie.replace(
    /(?:(?:^|.*;\s*)memberName\s*=\s*([^;]*).*$)|^.*$/,
    "$1"
  );
};

function deleteCookie(value) {
  document.cookie = `${value}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
}

export { getAuthFromCookie, getMemberNameFromCookie, deleteCookie };
  • utils에 쿠키와 관련된 함수를 작성하였다.
  • get 관련 함수는 백엔드 서버단에서 생성해준 쿠키를 반환하는 함수이다.
  • deleteCookie는 값을 매개변수로 받아서 해당하는 쿠키를 삭제한다.
// store/module/member.js
import memberService from "@/api/member";
import {
  getAuthFromCookie,
  getMemberNameFromCookie,
  deleteCookie,
} from "@/utils/cookies";

export const member = {
  state: {
    token: getAuthFromCookie() || "",
    memberName: getMemberNameFromCookie() || "",
  },
  getters: {
    isLogin(state) {
      return state.memberName !== "";
    },
  },
  actions: {
    async register({ commit }, member) {
      const result = await memberService.register(member);
      console.log(result);
    },
    async login({ commit }, member) {
      const result = await memberService.login(member);
      commit("setToken", getAuthFromCookie());
      commit("setMemberName", getMemberNameFromCookie());
      return result;
    },
  },
  mutations: {
    setToken(state, token) {
      state.token = token;
    },
    setMemberName(state, memberName) {
      state.memberName = memberName;
    },
    logout(state) {
      (state.token = ""), (state.memberName = "");
      deleteCookie("jwt");
      deleteCookie("memberName");
    },
  },
};
  • 회원과 관련된 store이다.
  • 로그인 시 login api를 호출하여 백엔드 서버 단에서 쿠키에 토큰 값과 회원 이름을 저장해준다.
  • setToken과 setMemberName을 호출하여 쿠키에서 값을 꺼내와 state에 저장해준다.
  • 새로고침을 해도 token과 memberName은 쿠키에서 값을 꺼내오기 때문에 값이 초기화되지 않아서 상태를 유지한다.
  • 로그아웃 시에는 state와 쿠키 값을 삭제하고 login 페이지로 이동한다.

비로그인 시 url로 접근 제한

권한이 없는 경우에도 url로 페이지에 접근하는 것을 막기 위해 router에서 설정할 수 있다.

// router/index.js
import Vue from "vue";
import VueRouter from "vue-router";
import store from "@/store/index";

Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    redirect: "/login",
  },
  {
    path: "/login",
    name: "Login",
    component: () => import("@/views/Login.vue"),
  },
  {
    path: "/signup",
    name: "Signup",
    component: () => import("@/views/Signup.vue"),
  },
  {
    path: "/main",
    name: "Main",
    component: () => import("@/views/Main.vue"),
    meta: { auth: true },
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

router.beforeEach((to, from, next) => {
  if (to.meta.auth && !store.getters.isLogin) {
    alert("로그인 페이지로 이동합니다.");
    next("/login");
    return;
  }
  next();
});

export default router;
  • beforeEach는 라우터 네비게이션 가드로 라우팅이 발생하기 전에 실행되는 코드이다.
  • to는 이동하려는 페이지, from은 현재 페이지, next는 다음 페이지로 이동할 수 있도록 호출하는 API이다.
  • 접근 권한이 필요한 페이지에 meta 속성을 사용해 정의한다.
  • meta 속성과 실제로 권한이 있는지를 확인해서 접근 권한이 필요한 페이지에 권한이 없다면 alert창으로 오류 메시지를 띄우고 login 창으로 이동하는 코드이다.

태그:

카테고리:

업데이트: