2021. 12. 12. 15:30ㆍSpring Security/Vue 3 Authentication with JWT
토큰의 갱신 및 권한의 체크는 Axios Interceptor를 이용하여서 처리한다.
토큰 갱신
로그인을 하게 되면 서버에서는 AccessToken과 RefreshToken을 발급하게 됩니다. 프로젝트에서는 테스트를 위해서 AccessToken의 만료 시간은 2분 RefrshToken의 만료 시간을 5분으로 설정하였습니다.
토큰 업데이트 프로세스
1. Reqeust Header AccessToken, 사용자 이름을 설정하여서 Back-end API를 호출한다.
2. Back-end의 JwtFilter에서는 AccessToken의 유효성 체크 후 Token이 만료된 경우 새로 발급된 AccessToken을
Response Header에 포함하여서 결과 메시지와 함께 전송한다.
3. Axios Interceptor에서는 Local Storage의 토큰과 Response Header의 토큰을 비교한 후 변경이 된 경우 Local
Storage에 토큰 정보를 업데이트 처리한다.
4. 사용자가 호출한 페이지를 보여준다.
소스
views/Admin.vue
<template>
<div class="wrapper">
<h2>{{ msg }}</h2>
</div>
</template>
<script>
import UserService from '../services/user.service'
import { ref } from 'vue'
export default {
name: 'Admin',
setup() {
let msg = ref('')
UserService.getAuthorityTest('admin').then(
(response) => {
if (response.data) {
msg.value = response.data.msg
}
return response
},
(error) => {
return Promise.reject(error);
}
);
return { msg }
}
}
</script>
<style>
.wrapper {
display: flex;
justify-content: center;
}
h2 {
color: blueviolet;
}
</style>
services/user.service.js
Back-end API 호출
import axios from 'axios'
import authHeader from './auth-header'
const API_URL = 'http://localhost:7070/api/test/'
class UserService {
getAuthorityTest(prefix) {
return axios.get(API_URL + prefix, { headers: authHeader() });
}
}
export default new UserService();
토큰 업데이트 테스트
Admin 화면
관리자 화면 로딩 후 개발자 도구에서 Local Storage를 확인해보면 아래와 같이 정보가 저장되어 있는 것을 확인할 수 있다.
프로젝트에서는 AccessToken은 2분 RefreshToken은 5분 후에 만료되어 있도록 설정하였다.
2분 후에 접속 후 개발자 도구 console을 확인해보면 Axios Interceptor에서 남긴 로그 정보를 확인할 수 있을 것이다.
main.js
import { createApp } from 'vue'
import Axios from 'axios'
import App from './App.vue'
import router from './router'
import store from './store'
// global styles
import './assets/main.css'
// Add a response interceptor
Axios.interceptors.response.use(
(response) => {
console.log('★ Axios.interceptors.response executed.')
// LocalStorage 사용자 정보
let user = JSON.parse(localStorage.getItem('user'))
if (user) {
console.log('-----------------------------------------------------------------------------')
let currentAccessToken = user.accessToken
console.log('currentAccessToken : ', currentAccessToken)
// Header Acesstoken 정보
let newAccessToken = response.headers['accesstoken']
// LocalStorage Token 과 Header의 토큰이 같지 않으면 새로 발급받은 토큰을 업데이트 한다.
if (newAccessToken) {
console.log('newAccessToken : ', newAccessToken)
if (newAccessToken !== currentAccessToken) {
user.accessToken = newAccessToken
localStorage['user'] = JSON.stringify(user);
console.log('Token 정보가 업데이트 되었습니다.')
}
}
console.log('-----------------------------------------------------------------------------')
}
return response;
},
(error) => {
console.log('★ Axios.interceptors.respoonse error executed.')
console.log(error)
switch (error.response.status) {
case 401:
localStorage.removeItem('user');
router.push({ name: 'Login' })
break;
case 403:
console.log('[' + error.response.status + '] Error')
router.push({ name: 'Forbidden' })
break;
}
return Promise.reject(error);
}
);
createApp(App)
.use(store)
.use(router)
.mount('#app')
위의 소를 확인 해보면 Local Storage에 저장된 Token 정보와 Response Header의 Token 정보를 비교하여서 변경 사항이 있는 경우 Local Storage의 AccessToken 정보를 업데이트하는 것을 확인할 수 있다.
이렇게 되면 사용자가 로그인 상태로 사이트를 계속 사용할 수 있을 것이다.
권한 테스트
사용자 등록 페이지에서 신규 사용자를 생성한다. 기본적으로 사용자 등록을 하게 되면 권한은 사용자 권한만을 가지게 된다.
관리자는 백엔드에서 기본적으로 admin@gmail.com/admin으로 계정을 생성하게 해 두었다.
접근 권한은 서버쪽에서 Spring Security를 이용하여서 체크하게 된다.
아래 소스의 @PreAuthorize를 보면 ADMIN 역할을 가진 사용자만이 접속할 수 있도록 처리되어 있다.
@GetMapping("/admin")
@PreAuthorize("hasAnyRole('ADMIN')")
public ResponseEntity<Map<String,String>> admin(HttpServletRequest httpServletRequest
, HttpServletResponse httpServletResponse) throws Exception {
Map<String,String> retObj = new HashMap<>();
retObj.put("msg","Admin Page!!!!");
return new ResponseEntity<>(retObj, HttpStatus.OK);
}
일반 사용자 권한을 가진 사용자가 접근하게 되면 SecurityApiConfig 소스를 보면 accessDeniedHanlder에 정의된 에러 페이지에서 처리하게 된다.
신규 사용자로 로그인 후 위의 http://localhost:8080/admin 화면으로 접근하게 되면 접근 권한이 없기 때문에 위의 main.js에 보면 403 에러인 경우 Forbidden 페이지로 Redirect 처리한다.
'Spring Security > Vue 3 Authentication with JWT' 카테고리의 다른 글
로그인 (0) | 2021.12.11 |
---|---|
Vue3 프로젝트 설정 (0) | 2021.12.07 |
Vue3 프로젝트 개요 (0) | 2021.12.06 |