
--- client/resources/api/index.js
+++ client/resources/api/index.js
... | ... | @@ -7,58 +7,78 @@ |
7 | 7 |
} |
8 | 8 |
}); |
9 | 9 |
|
10 |
+// 요청 인터셉터 |
|
10 | 11 |
apiClient.interceptors.request.use( |
11 | 12 |
config => { |
12 |
- config.headers.Authorization = store.state.authorization; // 요청 시 AccessToken 추가 |
|
13 |
+ const token = store.state.authorization; // Access Token 가져오기 |
|
14 |
+ if (token) { |
|
15 |
+ config.headers.Authorization = token; // 단순히 토큰만 추가 |
|
16 |
+ } |
|
13 | 17 |
return config; |
14 | 18 |
}, |
15 | 19 |
error => { |
16 | 20 |
return Promise.reject(error); |
17 | 21 |
} |
18 |
-) |
|
22 |
+); |
|
19 | 23 |
|
24 |
+// 응답 인터셉터 |
|
20 | 25 |
apiClient.interceptors.response.use( |
21 | 26 |
response => { |
22 |
- console.log('Response Status:', response.status); // 응답 상태 출력 |
|
23 | 27 |
return response; |
24 | 28 |
}, |
25 | 29 |
async error => { |
26 |
- console.log('Error Response:', error.response.data); // 오류 응답 데이터 출력 |
|
27 |
- console.log('Error Status:', error.response.status); // 오류 상태 출력 |
|
28 |
- if (error.response.status == 403 && error.response.data.message == '접근 권한이 없습니다.') { |
|
29 |
- window.history.back(); |
|
30 |
- } |
|
31 | 30 |
const originalReq = error.config; |
32 |
- // 토큰의 만료기간이 끝난경우 |
|
33 |
- if (error.response.status == 401 && error.response.data.message == '로그인 시간이 만료되었습니다.' && !originalReq._retry) { |
|
34 |
- originalReq._retry = true; // 재요청 시도(한번만 실행) |
|
31 |
+ |
|
32 |
+ // 403 에러 처리 |
|
33 |
+ if (error.response.status === 403) { |
|
34 |
+ alert('접근 권한이 없습니다.'); |
|
35 |
+ window.history.back(); |
|
36 |
+ return Promise.reject(error); |
|
37 |
+ } |
|
38 |
+ |
|
39 |
+ // 401 에러 처리 (토큰 만료) |
|
40 |
+ if (error.response.status === 401 && error.response.data.message === '로그인 시간이 만료되었습니다.' && !originalReq._retry) { |
|
41 |
+ // 토큰 재발급 요청 |
|
35 | 42 |
try { |
36 |
- const res = await axios.post('/refresh/tknReissue.json', {}); |
|
37 |
- store.commit('setAuthorization', res.headers.authorization); // 새로 발급 받은 AccessToken 저장 |
|
38 |
- originalReq.headers.Authorization = store.state.authorization; // 새로 발급 받은 AccessToken을 기존 요청에 추가 |
|
39 |
- /** jwt토큰 디코딩 **/ |
|
40 |
- const base64String = store.state.authorization.split('.')[1]; |
|
41 |
- const base64 = base64String.replace(/-/g, '+').replace(/_/g, '/'); |
|
42 |
- const jsonPayload = decodeURIComponent(atob(base64).split('').map(c => { |
|
43 |
- return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); |
|
44 |
- }).join('')); |
|
45 |
- const mbr = JSON.parse(jsonPayload); |
|
46 |
- // const mbr = JSON.parse(decodeURIComponent(escape(window.atob(base64String)))); // jwt claim 추출 |
|
47 |
- store.commit("setUserNm", mbr.userNm); |
|
48 |
- store.commit('setRoles', mbr.roles); |
|
49 |
- /** jwt토큰 디코딩 **/ |
|
50 |
- return apiClient(originalReq); // 원래 요청 재시도 /pathname + search |
|
43 |
+ const res = await axios.post("/refresh/tknReissue.json", {}, { |
|
44 |
+ headers: { |
|
45 |
+ "Content-Type": "application/json; charset=UTF-8", |
|
46 |
+ }, |
|
47 |
+ }); |
|
48 |
+ |
|
49 |
+ // 응답 상태가 200일 경우에만 처리 |
|
50 |
+ if (res.status === 200) { |
|
51 |
+ // 새로 발급 받은 AccessToken 저장 |
|
52 |
+ store.commit('setAuthorization', res.headers.authorization); |
|
53 |
+ originalReq.headers.Authorization = store.state.authorization; // 새로 발급 받은 AccessToken을 기존 요청에 추가 |
|
54 |
+ |
|
55 |
+ // JWT 토큰 디코딩 |
|
56 |
+ const base64String = store.state.authorization.split('.')[1]; |
|
57 |
+ const base64 = base64String.replace(/-/g, '+').replace(/_/g, '/'); |
|
58 |
+ const jsonPayload = decodeURIComponent(atob(base64).split('').map(c => { |
|
59 |
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); |
|
60 |
+ }).join('')); |
|
61 |
+ const mbr = JSON.parse(jsonPayload); |
|
62 |
+ store.commit("setUserNm", mbr.userNm); // 사용자 이름 저장 |
|
63 |
+ store.commit('setRoles', mbr.roles); // 사용자 역할 저장 |
|
64 |
+ |
|
65 |
+ return apiClient(originalReq); // 원래 요청 재시도 |
|
66 |
+ } else { |
|
67 |
+ // 200이 아닌 경우 |
|
68 |
+ throw new Error("토큰 재발급 요청 실패"); |
|
69 |
+ } |
|
51 | 70 |
} catch (refreshError) { |
52 | 71 |
const redirect = window.location.pathname + window.location.search; |
53 | 72 |
sessionStorage.setItem("redirect", redirect); |
54 | 73 |
alert('세션이 종료되었습니다.\n로그인을 새로 해주세요.'); |
55 | 74 |
store.commit("setStoreReset"); |
56 |
- window.location = '/login.page'; |
|
75 |
+ window.location = '/login.page'; // 로그인 페이지로 리다이렉트 |
|
57 | 76 |
return Promise.reject(refreshError); |
58 | 77 |
} |
59 | 78 |
} |
79 |
+ |
|
60 | 80 |
return Promise.reject(error); |
61 | 81 |
} |
62 |
-) |
|
82 |
+); |
|
63 | 83 |
|
64 |
-export default apiClient;(파일 끝에 줄바꿈 문자 없음) |
|
84 |
+export default apiClient; |
--- client/views/App.vue
+++ client/views/App.vue
... | ... | @@ -1,4 +1,3 @@ |
1 |
-App.vue |
|
2 | 1 |
<template> |
3 | 2 |
<div class="wrapper"> |
4 | 3 |
<Header /> |
--- client/views/pages/AppStore.js
+++ client/views/pages/AppStore.js
... | ... | @@ -6,7 +6,6 @@ |
6 | 6 |
plugins: [createPersistedState()], |
7 | 7 |
state: { |
8 | 8 |
authorization: null, |
9 |
- refresh: null, // 리프레시 토큰을 추가 |
|
10 | 9 |
userId: null, // 사용자 ID 추가 |
11 | 10 |
loginId: null, // 로그인 ID 추가 |
12 | 11 |
userNm: null, // 사용자 이름 추가 |
... | ... | @@ -15,9 +14,6 @@ |
15 | 14 |
getters: { |
16 | 15 |
getAuthorization(state) { |
17 | 16 |
return state.authorization; // authorization 반환 |
18 |
- }, |
|
19 |
- getRefresh(state) { |
|
20 |
- return state.refresh; // 리프레시 토큰 반환 |
|
21 | 17 |
}, |
22 | 18 |
getUserNm(state) { |
23 | 19 |
return state.userNm; // 사용자 이름 반환 |
... | ... | @@ -29,9 +25,6 @@ |
29 | 25 |
mutations: { |
30 | 26 |
setAuthorization(state, newValue) { |
31 | 27 |
state.authorization = newValue; // authorization 설정 |
32 |
- }, |
|
33 |
- setRefresh(state, newValue) { |
|
34 |
- state.refresh = newValue; // 리프레시 토큰 설정 |
|
35 | 28 |
}, |
36 | 29 |
setLoginId(state, newValue) { |
37 | 30 |
state.loginId = newValue; // 로그인 ID 설정 |
... | ... | @@ -47,7 +40,6 @@ |
47 | 40 |
}, |
48 | 41 |
setStoreReset(state) { |
49 | 42 |
state.authorization = null; |
50 |
- state.refresh = null; // 리프레시 토큰 초기화 |
|
51 | 43 |
state.userNm = null; |
52 | 44 |
state.userId = null; |
53 | 45 |
state.roles = []; |
--- client/views/pages/user/MyInfo.vue
+++ client/views/pages/user/MyInfo.vue
... | ... | @@ -154,6 +154,8 @@ |
154 | 154 |
this.resetForm(); |
155 | 155 |
alert("비밀번호가 변경되었습니다."); |
156 | 156 |
window.location.reload(); // 페이지 새로 고침 |
157 |
+ } else { |
|
158 |
+ alert("비밀번호 변경이 실패되었습니다."); |
|
157 | 159 |
} |
158 | 160 |
} |
159 | 161 |
} |
... | ... | @@ -167,6 +169,8 @@ |
167 | 169 |
this.resetForm(); |
168 | 170 |
alert("회원정보가 변경되었습니다."); |
169 | 171 |
window.location.reload(); // 페이지 새로 고침 |
172 |
+ } else { |
|
173 |
+ alert("회원정보가 변경이 실패되었습니다."); |
|
170 | 174 |
} |
171 | 175 |
} |
172 | 176 |
} else { |
... | ... | @@ -177,6 +181,8 @@ |
177 | 181 |
this.resetForm(); |
178 | 182 |
alert("회원과 비밀번호를 변경되었습니다."); |
179 | 183 |
window.location.reload(); // 페이지 새로 고침 |
184 |
+ } else { |
|
185 |
+ alert("회원과 비밀번호 변경이 실패되었습니다."); |
|
180 | 186 |
} |
181 | 187 |
} |
182 | 188 |
} |
... | ... | @@ -190,6 +196,8 @@ |
190 | 196 |
this.resetForm(); |
191 | 197 |
alert("비밀번호가 변경되었습니다."); |
192 | 198 |
window.location.reload(); // 페이지 새로 고침 |
199 |
+ }else { |
|
200 |
+ alert("비밀번호 변경이 실패되었습니다."); |
|
193 | 201 |
} |
194 | 202 |
} |
195 | 203 |
} |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?