본문 바로가기
Dev/Vue.js

[Vue.js] Today I Learned - 라우터 심화

by dev_jsk 2020. 10. 28.
728x90
반응형

라우터 네비게이션 가드

뷰 라우터를 이용하여 특정 URL에 접근할 때 해당 URL의 접근을 막는것

라우터 네비게이션 가드 기초 코드

라우터 네비게이션 가드의 기초 코드를 알아보자

// src/route/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';

Vue.use(VueRouter);

const router = new VueRouter({
  mode: 'history',
  routes: [
    ...
  ],
});

// to: 이동할 페이지
// from: 현재 페이지
// next: 다음 페이지로 넘어갈 수 있게 호출하는 API
router.beforeEach((to, from, next) => {
  console.log(to);
  // next() 를 호출해야만 다음 페이지로 이동 가능하다.
  next();
});

export default router;

페이지별 인증 권한 설정

특정 페이지 별로 권한을 부여할 수 있다.

// src/routes/index.js
import Vue from 'vue';
import VueRouter from 'vue-router';
import store from '../store';

Vue.use(VueRouter);

const router = new VueRouter({
  mode: 'history',
  routes: [
    {
      path: '/',
      redirect: '/login',
    },
    {
      path: '/login',
      component: () => import('@/views/LoginPage.vue'),
    },
    {
      path: '/signup',
      component: () => import('@/views/SignupPage.vue'),
    },
    {
      path: '/main',
      component: () => import('@/views/MainPage.vue'),
      // 인증정보가 필요한 URL에만 meta 속성 사용
      meta: {
        auth: true,
      },
    },
    {
      path: '/add',
      component: () => import('@/views/PostAddPage.vue'),
      meta: {
        auth: true,
      },
    },
    {
      path: '/post/:id',
      component: () => import('@/views/PostEditPage.vue'),
      meta: {
        auth: true,
      },
    },
    {
      path: '*',
      component: () => import('@/views/NotFoundPage.vue'),
    },
  ],
});

router.beforeEach((to, from, next) => {
  // meta속성에 정의된 auth 값과 스토어에 정의된 로그인상태를 확인하여
  // 미로그인 상태일 경우 if문 진입
  if (to.meta.auth && !store.getters.isLogin) {
    console.log('인증이 필요합니다.');
    // 미로그인 상태일 경우 로그인 페이지로 이동
    next('/login');
    // return을 해주어야만 원하는 결과(로그인 페이지 이동)를 얻을 수 있다.
    // return을 해주지 않으면 if문을 빠져나가서 next()가 실행된다.
    return;
  }
  next();
});

export default router;

로그인 상태에 따른 로고 이동 링크 처리

현재 헤더의 로고 클릭 시 로그인 페이지로 이동하게 되는데 미로그인 상태일 경우엔 로그인 페이지, 로그인 상태일 경우 메인 페이지로 이동하도록 구현할 수 있다.

<!-- src/components/common/AppHeader.vue -->
<template>
  <header>
    <div>
      <!-- v-bind 사용 -->
      <router-link :to="logoLink" class="logo">
        TIL
        <span v-if="isUserLogin">by {{ $store.state.username }}</span>
      </router-link>
    </div>
    <div class="navigations">
      <!-- 1 -->
      <template v-if="isUserLogin">
        <a href="javascript:;" @click="logoutUser" class="logout-button">
          Logout
        </a>
      </template>
      <!-- 2 -->
      <template v-else>
        <router-link to="/login">로그인</router-link>
        <router-link to="/signup">회원가입</router-link>
      </template>
    </div>
  </header>
</template>

<script>
export default {
  computed: {
    isUserLogin() {
      return this.$store.getters.isLogin;
    },
    // 스토어에 저장된 로그인 상태값에 따라 메인 or 로그인 페이지로 이동처리
    logoLink() {
      return this.$store.getters.isLogin ? '/main' : '/login';
    },
  },
  methods: {
    logoutUser() {
      this.$store.commit('clearUsername');
      this.$router.push('/login');
    },
  },
};
</script>

로그아웃 수정

현재 로그아웃 기능이 정상적으로 동작하지 않는다. 왜냐하면 로그아웃 시 쿠키 정보를 제거하는 처리가 되어있지 않기 때문이다. 따라서 로그아웃 시 쿠키 정보를 제거함으로서 정상적인 로그아웃 기능을 구현할 수 있다.

<!-- src/utils/cookies.js -->
<script>
// 브라우저 저장소 내 쿠키 제거
function deleteCookie(value) {
  document.cookie = `${value}=; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
}

export {
  deleteCookie,
};
</script>

<!-- src/store/index.js -->
<script>
import Vue from 'vue';
import Vuex from 'vuex';
import {
  getAuthFromCookie,
  getUserFromCookie,
} from '@/utils/cookies';

Vue.use(Vuex);

export default new Vuex.Store({
  state: {
    username: getUserFromCookie() || '',
    token: getAuthFromCookie() || '',
  },
  getters: {
    isLogin(state) {
      return state.username !== '';
    },
  },
  mutations: {
    setUsername(state, username) {
      state.username = username;
    },
    // 스토어에 저장된 유저명 제거
    clearUsername(state) {
      state.username = '';
    },
    setToken(state, token) {
      state.token = token;
    },
    // 스토어에 저장된 토큰 제거
    clearToken(state) {
      state.token = '';
    },
  },
});
</script>

<!-- src/components/common/AppHeader.vue -->
<script>
// 쿠키 제거 함수 import
import { deleteCookie } from '@/utils/cookies';

export default {
  computed: {
    isUserLogin() {
      return this.$store.getters.isLogin;
    },
    logoLink() {
      return this.$store.getters.isLogin ? '/main' : '/login';
    },
  },
  methods: {
    logoutUser() {
      // 스토어에 저장된 유저명, 토큰 제거
      this.$store.commit('clearUsername');
      this.$store.commit('clearToken');
      // 쿠키에 저장된 auth, user 제거
      deleteCookie('til_auth');
      deleteCookie('til_user');
      // 로그인 페이지로 이동
      this.$router.push('/login');
    },
  },
};
</script>
728x90
반응형

댓글