
Merge branch 'master' of http://210.180.118.83/jhpark/cms_frontend
@995da79e192fc9289f78b211ff30d50a152b6354
--- client/resources/api/index.js
+++ client/resources/api/index.js
... | ... | @@ -19,16 +19,24 @@ |
19 | 19 |
) |
20 | 20 |
|
21 | 21 |
apiClient.interceptors.response.use( |
22 |
+ |
|
22 | 23 |
response => { |
23 | 24 |
return response; |
24 | 25 |
}, |
25 | 26 |
async error => { |
27 |
+ if (!error.response) { |
|
28 |
+ return Promise.reject(error); |
|
29 |
+ } |
|
26 | 30 |
if (error.response.status == 403 && error.response.data.message == '접근 권한이 없습니다.') { |
27 | 31 |
window.history.back(); |
28 | 32 |
} |
29 | 33 |
const originalReq = error.config; |
34 |
+ if (originalReq.url.includes('/refresh/tokenReissue.json')) { |
|
35 |
+ return Promise.reject(error); |
|
36 |
+ } |
|
30 | 37 |
// 토큰의 만료기간이 끝난경우 |
31 |
- if (error.response.status == 401 && error.response.data.message == 'Token expired' && !originalReq._retry) { |
|
38 |
+ // if (error.response.status == 401 && error.response.data.message == 'Token expired' && !originalReq._retry) { |
|
39 |
+ if (error.response.status === 401 && error.response.data?.message?.toLowerCase().includes('expired') && !originalReq._retry) { |
|
32 | 40 |
originalReq._retry = true; // 재요청 시도(한번만 실행) |
33 | 41 |
try { |
34 | 42 |
const res = await axios.post('/refresh/tokenReissue.json', {}); |
... | ... | @@ -49,7 +57,7 @@ |
49 | 57 |
} catch (refreshError) { |
50 | 58 |
const redirect = window.location.pathname + window.location.search; |
51 | 59 |
sessionStorage.setItem("redirect", redirect); |
52 |
- alert('세션이 종료되었습니다.\n로그인을 새로 해주세요.'); |
|
60 |
+ alert('세션이 종료 되었습니다.\n로그인을 새로 해주세요.'); |
|
53 | 61 |
store.commit("setStoreReset"); |
54 | 62 |
window.location = '/login.page'; |
55 | 63 |
return Promise.reject(refreshError); |
+++ client/resources/api/loginPolicy
... | ... | @@ -0,0 +1,17 @@ |
1 | +import apiClient from "./index"; | |
2 | + | |
3 | +export const findAllByLoginPolicy = () => { | |
4 | + return apiClient.post(`/admin/loginPolicy/getLoginPolicy.json`); | |
5 | +} | |
6 | + | |
7 | +export const saveByLoginPolicy = loginPolicy => { | |
8 | + return apiClient.post(`/admin/loginPolicy/saveLoginPolicy.json`, loginPolicy); | |
9 | +} | |
10 | + | |
11 | +export const findAllByLoginMode = () => { | |
12 | + return apiClient.post(`/admin/loginPolicy/getLoginMode.json`); | |
13 | +} | |
14 | + | |
15 | +export const saveByLoginMode = loginMode => { | |
16 | + return apiClient.post(`/admin/loginPolicy/saveLoginMode.json`, loginMode); | |
17 | +}(파일 끝에 줄바꿈 문자 없음) |
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
... | ... | @@ -0,0 +1,114 @@ |
1 | +<template> | |
2 | + <div class="content admin-style"> | |
3 | + <div class="admin-page-title point-font2 mb30"> | |
4 | + <p>로그인 정책 설정</p> | |
5 | + </div> | |
6 | + <details open class="form-table-style mb30"> | |
7 | + <summary class="point-font2"> | |
8 | + <p class="summary-style pl10">로그인 정책</p> | |
9 | + </summary> | |
10 | + <div class="pt10 pb10"> | |
11 | + <table class="form-table"> | |
12 | + <colgroup> | |
13 | + <col width="50%" /> | |
14 | + <col width="50%" /> | |
15 | + </colgroup> | |
16 | + <tr> | |
17 | + <td> | |
18 | + <div class="gd-12 pl0"> | |
19 | + <label for="" class="form-title point-font2 mb10">중복로그인 설정</label> | |
20 | + <label> | |
21 | + <input type="checkbox" v-model="allowMultipleLogin" @change="saveByLoginPolicy" /> | |
22 | + </label> | |
23 | + <p>{{ allowMultipleLogin ? '중복 로그인을 허용하고 있습니다.' : '중복 로그인을 허용하지 않습니다.' }}</p> | |
24 | + <p style="color: red;"> ※ 로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.</p> | |
25 | + </div> | |
26 | + </td> | |
27 | + <td> | |
28 | + <div class="gd-12 pl0"> | |
29 | + <label for="" class="form-title point-font2 ">로그인 방식 설정</label> | |
30 | + <div class="gd-4"> | |
31 | + <input type="radio" class="mr5" value="J" v-model="lgnMode" @change="saveByLoginMode" /> | |
32 | + <label>JWT 방식</label> | |
33 | + </div> | |
34 | + <div class="gd-4"> | |
35 | + <input type="radio" class="mr5" value="S" v-model="lgnMode" @change="saveByLoginMode" /> | |
36 | + <label>SESSION 방식</label> | |
37 | + </div> | |
38 | + <span class="ml10 gray"> | |
39 | + 현재 로그인 방식은 <strong>{{ loginModeLabel }}</strong> 입니다. | |
40 | + </span> | |
41 | + | |
42 | + </div> | |
43 | + </td> | |
44 | + </tr> | |
45 | + </table> | |
46 | + </div> | |
47 | + </details> | |
48 | + </div> | |
49 | +</template> | |
50 | + | |
51 | + <script> | |
52 | + import { findAllByLoginPolicy, saveByLoginPolicy, findAllByLoginMode, saveByLoginMode } from '../../../../../resources/api/loginPolicy' | |
53 | + | |
54 | + export default { | |
55 | + data() { | |
56 | + return { | |
57 | + allowMultipleLogin: null, | |
58 | + lgnMode : null | |
59 | + } | |
60 | + }, | |
61 | + created() { | |
62 | + this.findAll(); | |
63 | + }, | |
64 | + mounted() { | |
65 | + }, | |
66 | + computed: { | |
67 | + loginModeLabel() { | |
68 | + return this.loginMode === 'J' ? 'JWT' : 'SESSION'; | |
69 | + } | |
70 | + }, | |
71 | + methods: { | |
72 | + async findAll() { | |
73 | + try { | |
74 | + const res1 = await findAllByLoginPolicy(); | |
75 | + this.allowMultipleLogin = res1.data.data; | |
76 | + | |
77 | + const res2 = await findAllByLoginMode(); | |
78 | + this.lgnMode = res2.data.data; | |
79 | + | |
80 | + } catch (err) { | |
81 | + alert('설정 정보를 불러오는 데 실패했습니다.'); | |
82 | + } | |
83 | + }, | |
84 | + async saveByLoginPolicy() { | |
85 | + try { | |
86 | + const loginPolicy = {}; | |
87 | + loginPolicy.allowMultipleLogin = this.allowMultipleLogin ? "Y" : "N"; | |
88 | + // await saveByLoginPolicy(loginPolicy); | |
89 | + alert('중복 로그인 설정이 저장되었습니다.'); | |
90 | + } catch (err) { | |
91 | + alert('중복 로그인 설정 저장 실패'); | |
92 | + } | |
93 | + }, | |
94 | + async saveByLoginMode() { | |
95 | + const confirmed = confirm( | |
96 | + '로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' | |
97 | + ); | |
98 | + if (!confirmed) return; | |
99 | + | |
100 | + try { | |
101 | + const loginMode = {}; | |
102 | + loginMode.lgnMode = this.lgnMode; | |
103 | + // await saveByLoginMode(loginMode); | |
104 | + alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.'); | |
105 | + store.commit("setStoreReset"); | |
106 | + window.location = '/login.page'; | |
107 | + return Promise.reject(refreshError); | |
108 | + } catch (err) { | |
109 | + alert('로그인 방식 저장 실패', err); | |
110 | + } | |
111 | + } | |
112 | + } | |
113 | + } | |
114 | + </script>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
... | ... | @@ -100,31 +100,35 @@ |
100 | 100 |
try { |
101 | 101 |
const res = await loginProc(this.member); |
102 | 102 |
if (res.status == 200) { |
103 |
- store.commit("setAuthorization", res.headers.authorization); |
|
104 |
- // store.commit("setRefresh", res.headers.refresh); |
|
105 |
- /** jwt토큰 복호화 **/ |
|
106 |
- const base64String = store.state.authorization.split(".")[1]; |
|
107 |
- const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/"); |
|
108 |
- const jsonPayload = decodeURIComponent( |
|
109 |
- atob(base64) |
|
110 |
- .split("") |
|
111 |
- .map((c) => { |
|
112 |
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); |
|
113 |
- }) |
|
114 |
- .join("") |
|
115 |
- ); |
|
116 |
- const mbr = JSON.parse(jsonPayload); |
|
117 |
- //const mbr = JSON.parse(decodeURIComponent(escape(window.atob(base64String)))); // jwt claim 추출 |
|
118 |
- store.commit("setMbrId", mbr.mbrId); |
|
119 |
- store.commit("setMbrNm", mbr.mbrNm); |
|
120 |
- store.commit("setRoles", mbr.roles); |
|
121 |
- /** jwt토큰 복호화 **/ |
|
103 |
+ const loginType = res.headers['login-type']; // 세션/토큰 로그인 구분 |
|
104 |
+ if (loginType === 'J') { |
|
105 |
+ // JWT 방식 |
|
106 |
+ store.commit("setAuthorization", res.headers.authorization); |
|
107 |
+ const base64String = store.state.authorization.split(".")[1]; |
|
108 |
+ const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/"); |
|
109 |
+ const jsonPayload = decodeURIComponent( |
|
110 |
+ atob(base64).split("").map((c) => { |
|
111 |
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); |
|
112 |
+ }).join("") |
|
113 |
+ ); |
|
114 |
+ const mbr = JSON.parse(jsonPayload); |
|
115 |
+ store.commit("setMbrId", mbr.mbrId); |
|
116 |
+ store.commit("setMbrNm", mbr.mbrNm); |
|
117 |
+ store.commit("setRoles", mbr.roles); |
|
118 |
+ } else if (loginType === 'S') { |
|
119 |
+ // 세션 방식 (서버에서 따로 body에 사용자 정보 내려줘야 함) |
|
120 |
+ const mbr = res.data; |
|
121 |
+ store.commit("setAuthorization", null); |
|
122 |
+ store.commit("setMbrId", mbr.mbrId); |
|
123 |
+ store.commit("setMbrNm", mbr.mbrNm); |
|
124 |
+ store.commit("setRoles", mbr.roles); |
|
125 |
+ } else { |
|
126 |
+ alert("알 수 없는 로그인 방식입니다."); |
|
127 |
+ return; |
|
128 |
+ } |
|
122 | 129 |
const url = this.restoreRedirect("redirect"); |
123 | 130 |
if (url != null && url != "") { |
124 |
- if ( |
|
125 |
- url == "/searchId.page" || |
|
126 |
- url == "/resetPswd.page" |
|
127 |
- ) { |
|
131 |
+ if (url == "/searchId.page" || url == "/resetPswd.page") { |
|
128 | 132 |
this.$router.push({ path: "/main.page" }); |
129 | 133 |
} else { |
130 | 134 |
this.$router.push({ path: url }); |
... | ... | @@ -145,7 +149,7 @@ |
145 | 149 |
}, |
146 | 150 |
}); |
147 | 151 |
}, |
148 |
- moveResetPswd() { |
|
152 |
+ moveResetPswd() { |
|
149 | 153 |
this.$router.push({ |
150 | 154 |
path: "/resetPswd.page", |
151 | 155 |
query: { |
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?