JWT로 인증하는 로그인/회원가입 서비스를 기존 프로젝트에 추가할 것이다.
JWT를 조금 더 안전하게 저장하는 방법으로 regen token을 사용하여 토큰이 만료되면 사용자에게 바로 연장 요청을 하는 기능을 구현하는 과정을 기록한다.
store/userStore.ts
id와 token 값을 관리할 pinia store를 만들어준다.
import { defineStore } from 'pinia';
export const useUserStore = defineStore({
id: 'main',
state: () => ({
id: '',
token: '',
}),
getters: {
isLogin: (state) => {
return state.id !== '';
},
},
actions: {
setUsername(id: string) {
this.id = id;
},
clearUsername() {
this.id = '';
},
setToken(token: string) {
this.token = token;
}
},
});
그 다음, LoginView.vue 파일을 만들고 로그인 폼을 간단하게 만든다. 아이디와 비밀번호를 입력 받는다.
<template>
<div class="column items-center">
<div class="col q-pa-lg">
<q-img src="/src/assets/login.png" style="width: 300px; height: 50px;" />
</div>
<div class="col" style="max-width: 400px; margin-top: -100px;">
<h6><b>로그인</b></h6>
<q-form @submit="onSubmit" class="q-gutter-md">
<q-input filled v-model="id" label="아이디 *" lazy-rules
:rules="[(val: string | any[]) => val && val.length > 0 || '아이디를 입력해주세요']" />
<q-input filled v-model="pw" label="비밀번호 *" lazy-rules
:rules="[(val: string | any[]) => val && val.length > 0 || '비밀번호를 입력해주세요']"/> <div>
<q-btn label="login" type="submit" color="primary" class="q-ml-sm" />
<q-btn label="signup" to="/Signup" color="secondary" class="q-ml-lg" />
</div>
</q-form>
</div>
</div>
</template>
백엔드 서버 구축해 놓은 부분을 연결해보자. 그리고 로그인 시 받아온 id와 백엔드에서 받은 token 값을 store에 저장한다.
<script setup lang="ts">
import { useQuasar } from 'quasar'
import { ref } from 'vue'
import axios from 'axios';
import { useRouter } from 'vue-router';
import { useUserStore } from "../store/userStore";
const $q = useQuasar()
const router = useRouter();
const userStore = useUserStore();
const id = ref<string>('');
const pw = ref<string>('');
const onSubmit = async () => {
try {
const userData = {
id: id.value,
pw: pw.value,
};
const { data } = await axios.post("/login", userData);
console.log(data);
userStore.setUsername(userData.id);
userStore.setToken(data.token);
$q.notify({
color: 'green-4',
textColor: 'white',
icon: 'cloud_done',
message: '로그인 성공'
})
router.push({ path: '/Home' });
}
catch (error) {
console.log(error);
$q.notify({
color: 'red-5',
textColor: 'white',
icon: 'warning',
message: '아이디와 비밀번호가 일치하지 않습니다'
})
} finally {
id.value = '';
pw.value = '';
}
};
</script>
상단바 Layout에서 사용자 활동을 관리하도록 할 것이다.
<template v-if="isUserLogin()">
<div class="q-gutter-x-md">
<span> {{ userStore.id }} 님 환영합니다!</span>
<q-btn color="secondary"><a href="javascript:;" @click="logoutUser"
style="text-decoration: none; color: white;">Logout</a></q-btn>
</div>
</template>
<script setup lang="ts">
import { useUserStore } from "../store/userStore";
import { useRouter } from 'vue-router';
const router = useRouter();
const userStore = useUserStore();
const logoutUser = () => {
userStore.clearUsername();
router.push({ path: '/Login' });
}
const isUserLogin = () => {
return userStore.isLogin;
};
</script>
여기까지 완료하면 백엔드에서 임시로 구축해둔 아이디와 비밀번호로 로그인이 가능하다.
다음은 JWT 핸들링하여 토큰 만료 시간을 계산한 후 알림창을 띄워주고 regen token을 갱신시키도록 하겠다.