- [Vue 3] Router 사용하기에 store를 추가하여 navigation guard를 구현하고자 한다.
- userStore에 user 정보가 있으면 로그인한 사용자로 판단하여
/
로, user 정보가 없으면 로그인하지 않은 사용자이므로/login
으로 이동하도록 구현한다.
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({
username: null,
}),
getters: {
isLoggedIn: (state) => {
return state.username != null;
},
},
actions: {},
});
import { route } from "quasar/wrappers";
import {
createRouter,
createMemoryHistory,
createWebHistory,
createWebHashHistory,
} from "vue-router";
import { useUserStore } from "src/stores/user-store";
import routes from "./routes";
export default route(function (/* { store, ssrContext } */) {
const createHistory = process.env.SERVER
? createMemoryHistory
: process.env.VUE_ROUTER_MODE === "history"
? createWebHistory
: createWebHashHistory;
const Router = createRouter({
scrollBehavior: () => ({ left: 0, top: 0 }),
routes,
history: createHistory(process.env.VUE_ROUTER_BASE),
});
// 추가한 부분
const userStore = useUserStore();
Router.beforeEach((to, from, next) => { // 페이지를 이동하기 전에 호출되는 함수
if (to.fullPath !== "/login" && !userStore.isLoggedIn) {
// /login으로 가고 있지 않고 로그인되어 있지 않으면 /login으로 redirect
// 로그인하지 않은 상태에서 /를 요청하는 경우 (프로젝트가 처음 실행될 때)
next("/login");
} else if (to.fullPath == "/login" && userStore.isLoggedIn) {
// /login으로 가고 있고 로그인되어 있으면 /으로 redirect
// 로그인한 상태에서 /login을 요청하는 경우
next("/");
} else {
next();
}
});
return Router;
});
to.fullPath
를 체크하는 이유는 무한 리디렉션을 방지하기 위함이다.
<template>
<q-layout>
<q-page-container>
<router-view />
</q-page-container>
</q-layout>
</template>
<router-view>
태그의 위치에 routes.js 파일에서 설정한 component가 위치한다.const routes = [
{
path: "/",
component: () => import("layouts/RouteLayout.vue"),
children: [
{
path: "",
component: () => import("pages/HomePage.vue"),
},
{
path: "login",
component: () => import("pages/LoginPage.vue"),
},
],
},
{
path: "/:catchAll(.*)*",
component: () => import("pages/ErrorNotFound.vue"),
},
];
export default routes;
/
인 경우 RouteLayout.vue 위에 HomePage.vue를 component로 위치/login
인 경우 RouteLayout.vue 위에 LoginPage.vue를 component로 위치<template>
<q-page>
<router-link to="/">Home</router-link><q-space /> Login Page<q-space />
<q-btn @click="login">Login</q-btn>
</q-page>
</template>
<script setup>
import { useUserStore } from "src/stores/user-store";
import { useRouter } from "vue-router";
const userStore = useUserStore();
const router = useRouter();
const login = () => {
userStore.username = "test";
if (userStore.isLoggedIn) { // pinia에서는 getter를 필드처럼 사용 가능하다.
// 로그인 성공 시 페이지 이동
router.push("/");
}
};
</script>
실행 화면
로그인 버튼을 클릭하면 /
으로 이동한다.
로그인 버튼을 누르지 않은 상황에서는 Home 페이지로 가는 버튼을 눌러도 이동하지 않는다.
<template>
<q-page>
<router-link to="/login">Login</router-link><q-space /> Home Page<q-space />
{{ username }}님 안녕하세요.<q-space />
<q-btn @click="logout">Logout</q-btn>
</q-page>
</template>
<script setup>
import { useUserStore } from "src/stores/user-store";
import { useRouter } from "vue-router";
const userStore = useUserStore();
const username = userStore.username;
const router = useRouter();
const logout = () => {
userStore.username = null;
if (!userStore.isLoggedIn) {
// 로그아웃 성공 시 페이지 이동
router.push("/login");
}
};
</script>
실행 화면
로그아웃 버튼을 클릭하면 /login
으로 이동한다.
로그아웃 버튼을 누르지 않은 상황에서는 Login 페이지로 가는 버튼을 눌러도 이동하지 않는다.