[Vue] Vue Router 내비게이션 가드 / 로그인 기능 구현 (pinia-persistedstate)

2024. 12. 26. 12:47· FE/Vue.js
목차
  1. 로그인 방식
  2. 로그인 여부 확인 방법
  3. Vue Router 접근 권한 설정
  4. Pinia Store 활용해서 로그인 기능 구현 (새로고침 시 초기화)
  5. pinia-plugin-persistedstate
728x90

로그인 방식

세션 로그인 방식

  • 백엔드 서버에 로그인했다는 정보를 저장

토큰 로그인 방식

  • 클라이언트에 로그인했다는 정보를 저장

 


로그인 여부 확인 방법

1. 서버로 쿠키를 주고 받는다. (백엔드를 통해서 확인)

  • 장점: 클라이언트가 조작하기 어려움
  • 단점: 백엔드 부하 증가

 

2. 웹 브라우저에서 HttpOnly가 아닌 일반 쿠키 또는 스토리지에 로그인 했다는 정보를 저장한다.

  • 장점: 백엔드에게 물어보지 않아도 바로 로그인 여부 확인 가능, 백엔드 부하 감소
  • 단점: 클라이언트가 조작하기 어려움

 


Vue Router 접근 권한 설정

라우터 파일을 통해 접근 권한을 설정한다.

접근 권한을 설정하고 싶은 경로에 beforeEnter: 함수 를 넣어준다.

 { path: "/a", component: A, beforeEnter: checkLogin }

 

router/index.js

더보기
import { createRouter, createWebHistory } from "vue-router";
import A from "../components/A.vue";
import B from "../components/B.vue";
import Login from "../components/Login.vue";
const checkLogin = (from, to, next) => {
// 로그인을 확인하는 코드 실행
if (false) {
return next();
}
next("/user/login");
};
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: "/a", component: A, beforeEnter: checkLogin },
{ path: "/b", component: B },
{ path: "/user/login", component: Login },
],
});
export default router;

 

App.vue

<script setup>
</script>
<template>
<ul>
<li>
<router-link to="/a">A</router-link>
</li>
<li>
<router-link to="/b">B</router-link>
</li>
</ul>
<router-view></router-view>
</template>
<style scoped></style>

 

 

/b는 접근 권한 설정이 안 되어 있기 때문에 아무나 접근할 수 있다.

 

A로 가려고 할 때 접근이 되지 않고 /user/login 경로로 강제로 이동한다.

A 눌렀을 때 /a로 경로 이동하지 않고 /user/login으로 경로 이동

 

 


Pinia Store 활용해서 로그인 기능 구현 (새로고침 시 초기화)

아래의 방법은 로그인 확인 방법 중 서버로 쿠키를 주고 받는 방법을 사용한 것이다.

 

useUserStore.js

isLogin이라는 변수를 만들어서 login이 될 때 `true`로 바꿔준다.

`loginCheck`는 ATOKEN 쿠키가 있으면 isSuccess: true라는 데이터가 온다.

더보기
import axios from "axios";
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({ isLogin: false }),
actions: {
async signUp(signUpData) {
const response = await axios.post("/api/user/signup", signUpData);
return response.data;
},
async login(loginData) {
const response = await axios.post("/api/login", loginData);
if (response.data.isLogin) {
this.isLogin = true;
}
return response;
},
async loginCheck() {
const response = await axios.get("/api/user/auth/check", {
withCredentials: true,
});
if (response.data.isSuccess) {
this.isLogin = true;
}
return response.data;
},
},
});

 

 

router/index.js

/a 경로로 이동할 때 checkLogin 함수를 실행해서 userStore의 loginCheck 함수로 쿠키 토큰이 있는지 확인한다.

더보기
import { createRouter, createWebHistory } from "vue-router";
import A from "../components/A.vue";
import B from "../components/B.vue";
import Login from "../components/Login.vue";
import { useUserStore } from "../stores/useUserStore";
import Logout from "../components/Logout.vue";
const checkLogin = async (from, to, next) => {
//로그인을 확인하는 코드 실행
const userStore = useUserStore();
await userStore.loginCheck();
if (userStore.isLogin) {
return next();
}
next("/user/login");
};
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: "/a", component: A, beforeEnter: checkLogin },
{ path: "/b", component: B },
{ path: "/user/login", component: Login },
{ path: "/user/logout", component: Logout },
],
});
export default router;

 

Login.vue

로그인 버튼을 눌렀을 때 userStore의 login 함수를 실행한다.

더보기
<script setup>
import { ref } from "vue";
import { useUserStore } from "../stores/useUserStore";
import router from "../router";
const loginData = ref({
username: "",
password: "",
});
const userStore = useUserStore();
const login = async () => {
const result = await userStore.login(loginData.value);
console.log(result);
};
</script>
<template>
<div>
<p>이메일</p>
<input type="email" v-model="loginData.username" />
<p>비밀번호</p>
<input type="password" v-model="loginData.password" />
<button @click="login">로그인</button>
</div>
</template>
<style scoped>
/* style 생략 */
</style>

 

 

App.vue

더보기
<script setup>
import { useUserStore } from "./stores/useUserStore";
const userStore = useUserStore();
</script>
<template>
<ul>
<li v-if="userStore.isLogin">
<router-link to="/user/logout">Logout</router-link>
</li>
<li v-else>
<router-link to="/user/login">Login</router-link>
</li>
<li>
<router-link to="/a">A</router-link>
</li>
<li>
<router-link to="/b">B</router-link>
</li>
</ul>
<router-view></router-view>
</template>
<style scoped></style>

 

 

로그인을 하면 개발자 도구 - 애플리케이션 - 쿠키 탭에 ATOKEN으로 토큰이 들어와있다.

 

 

이렇게 하면 로그인 했을 때 쿠키는 들어오지만, 새로고침 하면 다시 Login이 풀리는 것을 확인할 수 있다.

맨 위에 Logout 버튼이 새로고침 하면 다시 Login으로 바뀐다.

 

 

이러한 일이 발생하는 이유는 useUserStore 때문이다.

 

store를 사용하는 컴포넌트가 화면에 보여지면서 사용이 될 때, 컴포넌트 객체가 생성이 되면서 안에서 쓰는 store 객체도 새로 만들어진다.

객체가 없어졌다가 새로 생기면 안에 있던 변수가 초기값으로 초기화된다.

-> 컴포넌트가 사용이 될 때마다 변수값이 계속 초기화된다.

 

=> 페이지를 이동해도 변수값을 유지하는 기능이 필요하다. (추가 라이브러리 pinia-plugin-persistedstate 설치)

 

 


pinia-plugin-persistedstate

설치

npm install pinia-plugin-persistedstate


사용

main.js에 piniaPersistedstate를 추가해준다.

 

main.js

import piniaPersistedstate from "pinia-plugin-persistedstate";
const pinia = createPinia();
pinia.use(piniaPersistedstate);
// app 부분 생략

 

 

store 파일에 persist를 추가해준다.

보통 로그인은 세션 스토리지를 사용하기 때문에 세션 스토리지에 저장해준다.

persist: {
storage: sessionStorage,
},

 

 

useUserStore.js

persist를 추가해준다.

더보기
import axios from "axios";
import { defineStore } from "pinia";
export const useUserStore = defineStore("user", {
state: () => ({ isLogin: false }),
persist: {
storage: sessionStorage,
},
actions: {
async signUp(signUpData) {
const response = await axios.post("/api/user/signup", signUpData);
return response.data;
},
async login(loginData) {
const response = await axios.post("/api/login", loginData);
if (response.data.isLogin) {
this.isLogin = true;
}
return response;
},
async loginCheck() {
const response = await axios.get("/api/user/auth/check", {
withCredentials: true,
});
if (response.data.isSuccess) {
this.isLogin = true;
}
return response.data;
},
},
});

 

개발자 도구 - 애플리케이션 - 세션 저장소 에 값이 들어와있다.

728x90
저작자표시 비영리 변경금지 (새창열림)

'FE > Vue.js' 카테고리의 다른 글

[Vue] Pinia 설치 / Store 사용 (loading, axios)  (0) 2024.12.23
[Vue] 컴포넌트 간 데이터 주고받기 (Props, Emit)  (1) 2024.12.23
[Vue] 데이터 바인딩 (ref, reactive) / 조건문, 반복문 (v-if, v-for) / v-model  (0) 2024.12.20
[Vue] Vue Router란? / Vue Router 사용 (router-link, useRouter)  (1) 2024.12.20
[Vue] VSCode에서 Vue.js 템플릿 설정 (Vue.js Snippet)  (2) 2024.12.20
  1. 로그인 방식
  2. 로그인 여부 확인 방법
  3. Vue Router 접근 권한 설정
  4. Pinia Store 활용해서 로그인 기능 구현 (새로고침 시 초기화)
  5. pinia-plugin-persistedstate
'FE/Vue.js' 카테고리의 다른 글
  • [Vue] Pinia 설치 / Store 사용 (loading, axios)
  • [Vue] 컴포넌트 간 데이터 주고받기 (Props, Emit)
  • [Vue] 데이터 바인딩 (ref, reactive) / 조건문, 반복문 (v-if, v-for) / v-model
  • [Vue] Vue Router란? / Vue Router 사용 (router-link, useRouter)
셰욘
셰욘
셰욘
seiyeon
셰욘
전체
오늘
어제
  • 분류 전체보기 (176)
    • 알고리즘 (46)
      • 프로그래머스 (2)
      • 백준 (37)
      • 문제 유형 (7)
    • CS (41)
      • Linux (6)
      • DB (15)
      • 자료구조 (3)
      • OOP (2)
      • 아키텍처 (0)
    • BE (42)
      • Java (9)
      • Spring Boot (32)
    • FE (6)
      • Next.js (1)
      • JavaScript (5)
      • Vue.js (7)
      • Web (0)
    • 배포 (5)
    • 회고 (19)
      • BEYOND SW 캠프 (19)
    • 기타 (3)

블로그 메뉴

  • 홈
  • 태그
  • 방명록
  • 블로그 관리

공지사항

인기 글

태그

  • 우선순위 큐
  • 회고
  • Java
  • 네트워크
  • spring boot
  • Gateway
  • DP
  • bfs
  • web
  • 주간회고
  • fe
  • be
  • dfs
  • 백트래킹
  • cs
  • 프로그래머스
  • 구현
  • 백준
  • js
  • db
  • 티스토리챌린지
  • 실습
  • 트리
  • 오블완
  • 그리디
  • 알고리즘
  • 자료구조
  • AWS
  • vue
  • 리눅스

최근 댓글

최근 글

250x250
hELLO · Designed By 정상우.v4.2.1
셰욘
[Vue] Vue Router 내비게이션 가드 / 로그인 기능 구현 (pinia-persistedstate)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.