

250328 김혜민 로그인정책 추가
@42f446071472b9e8cd1a6d1dc3ae47b55d1412c8
--- 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
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
... | ... | @@ -1,30 +1,52 @@ |
1 | 1 |
<template> |
2 |
- <div class="content admin-style"> |
|
3 |
- <div class="admin-page-title point-font2 mb30"> |
|
4 |
- <p>중복 로그인 허용 설정</p> |
|
5 |
- </div> |
|
6 |
- <label> |
|
7 |
- <input type="checkbox" v-model="allowMultipleLogin" @change="saveByLoginPolicy" /> |
|
8 |
- <span class="slider"></span> |
|
9 |
- </label> |
|
10 |
- <p>{{ allowMultipleLogin ? '중복 로그인을 허용하고 있습니다.' : '중복 로그인을 허용하지 않습니다.' }}</p> |
|
11 |
- <h2>로그인 방식 설정</h2> |
|
12 |
- <p style="color: red;"> ※ 로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.</p> |
|
13 |
- <div> |
|
14 |
- <label> |
|
15 |
- <input type="radio" value="J" v-model="loginMode" @change="updateLoginMode" /> |
|
16 |
- JWT 방식 |
|
17 |
- </label> |
|
18 |
- <label> |
|
19 |
- <input type="radio" value="S" v-model="loginMode" @change="updateLoginMode" /> |
|
20 |
- SESSION 방식 |
|
21 |
- </label> |
|
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> |
|
22 | 48 |
</div> |
23 |
- <p> |
|
24 |
- 현재 로그인 방식은 <strong>{{ loginModeLabel }}</strong> 입니다. |
|
25 |
- </p> |
|
26 |
- </div> |
|
27 |
- </template> |
|
49 |
+</template> |
|
28 | 50 |
|
29 | 51 |
<script> |
30 | 52 |
import { findAllByLoginPolicy, saveByLoginPolicy, findAllByLoginMode, saveByLoginMode } from '../../../../../resources/api/loginPolicy' |
... | ... | @@ -33,7 +55,7 @@ |
33 | 55 |
data() { |
34 | 56 |
return { |
35 | 57 |
allowMultipleLogin: null, |
36 |
- loginMode : null |
|
58 |
+ lgnMode : null |
|
37 | 59 |
} |
38 | 60 |
}, |
39 | 61 |
created() { |
... | ... | @@ -53,15 +75,17 @@ |
53 | 75 |
this.allowMultipleLogin = res1.data.data; |
54 | 76 |
|
55 | 77 |
const res2 = await findAllByLoginMode(); |
56 |
- this.loginMode = res2.data.data; |
|
57 |
- console.log("this.isAllowed", this.allowMultipleLogin); |
|
78 |
+ this.lgnMode = res2.data.data; |
|
79 |
+ |
|
58 | 80 |
} catch (err) { |
59 | 81 |
alert('설정 정보를 불러오는 데 실패했습니다.'); |
60 | 82 |
} |
61 | 83 |
}, |
62 | 84 |
async saveByLoginPolicy() { |
63 | 85 |
try { |
64 |
- await saveByLoginPolicy(this.allowMultipleLogin); |
|
86 |
+ const loginPolicy = {}; |
|
87 |
+ loginPolicy.allowMultipleLogin = this.allowMultipleLogin ? "Y" : "N"; |
|
88 |
+ // await saveByLoginPolicy(loginPolicy); |
|
65 | 89 |
alert('중복 로그인 설정이 저장되었습니다.'); |
66 | 90 |
} catch (err) { |
67 | 91 |
alert('중복 로그인 설정 저장 실패'); |
... | ... | @@ -74,14 +98,15 @@ |
74 | 98 |
if (!confirmed) return; |
75 | 99 |
|
76 | 100 |
try { |
77 |
- console.log(this.loginMode); |
|
78 |
- await saveByLoginMode(this.loginMode); |
|
101 |
+ const loginMode = {}; |
|
102 |
+ loginMode.lgnMode = this.lgnMode; |
|
103 |
+ // await saveByLoginMode(loginMode); |
|
79 | 104 |
alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
80 | 105 |
store.commit("setStoreReset"); |
81 | 106 |
window.location = '/login.page'; |
82 | 107 |
return Promise.reject(refreshError); |
83 | 108 |
} catch (err) { |
84 |
- alert('로그인 방식 저장 실패'); |
|
109 |
+ alert('로그인 방식 저장 실패', err); |
|
85 | 110 |
} |
86 | 111 |
} |
87 | 112 |
} |
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
... | ... | @@ -92,31 +92,35 @@ |
92 | 92 |
try { |
93 | 93 |
const res = await loginProc(this.member); |
94 | 94 |
if (res.status == 200) { |
95 |
- store.commit("setAuthorization", res.headers.authorization); |
|
96 |
- // store.commit("setRefresh", res.headers.refresh); |
|
97 |
- /** jwt토큰 복호화 **/ |
|
98 |
- const base64String = store.state.authorization.split(".")[1]; |
|
99 |
- const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/"); |
|
100 |
- const jsonPayload = decodeURIComponent( |
|
101 |
- atob(base64) |
|
102 |
- .split("") |
|
103 |
- .map((c) => { |
|
104 |
- return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); |
|
105 |
- }) |
|
106 |
- .join("") |
|
107 |
- ); |
|
108 |
- const mbr = JSON.parse(jsonPayload); |
|
109 |
- //const mbr = JSON.parse(decodeURIComponent(escape(window.atob(base64String)))); // jwt claim 추출 |
|
110 |
- store.commit("setMbrId", mbr.mbrId); |
|
111 |
- store.commit("setMbrNm", mbr.mbrNm); |
|
112 |
- store.commit("setRoles", mbr.roles); |
|
113 |
- /** jwt토큰 복호화 **/ |
|
95 |
+ const loginType = res.headers['login-type']; // 세션/토큰 로그인 구분 |
|
96 |
+ if (loginType === 'J') { |
|
97 |
+ // JWT 방식 |
|
98 |
+ store.commit("setAuthorization", res.headers.authorization); |
|
99 |
+ const base64String = store.state.authorization.split(".")[1]; |
|
100 |
+ const base64 = base64String.replace(/-/g, "+").replace(/_/g, "/"); |
|
101 |
+ const jsonPayload = decodeURIComponent( |
|
102 |
+ atob(base64).split("").map((c) => { |
|
103 |
+ return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2); |
|
104 |
+ }).join("") |
|
105 |
+ ); |
|
106 |
+ const mbr = JSON.parse(jsonPayload); |
|
107 |
+ store.commit("setMbrId", mbr.mbrId); |
|
108 |
+ store.commit("setMbrNm", mbr.mbrNm); |
|
109 |
+ store.commit("setRoles", mbr.roles); |
|
110 |
+ } else if (loginType === 'S') { |
|
111 |
+ // 세션 방식 (서버에서 따로 body에 사용자 정보 내려줘야 함) |
|
112 |
+ const mbr = res.data; |
|
113 |
+ store.commit("setAuthorization", null); |
|
114 |
+ store.commit("setMbrId", mbr.mbrId); |
|
115 |
+ store.commit("setMbrNm", mbr.mbrNm); |
|
116 |
+ store.commit("setRoles", mbr.roles); |
|
117 |
+ } else { |
|
118 |
+ alert("알 수 없는 로그인 방식입니다."); |
|
119 |
+ return; |
|
120 |
+ } |
|
114 | 121 |
const url = this.restoreRedirect("redirect"); |
115 | 122 |
if (url != null && url != "") { |
116 |
- if ( |
|
117 |
- url == "/searchId.page" || |
|
118 |
- url == "/resetPswd.page" |
|
119 |
- ) { |
|
123 |
+ if (url == "/searchId.page" || url == "/resetPswd.page") { |
|
120 | 124 |
this.$router.push({ path: "/main.page" }); |
121 | 125 |
} else { |
122 | 126 |
this.$router.push({ path: url }); |
... | ... | @@ -137,7 +141,7 @@ |
137 | 141 |
}, |
138 | 142 |
}); |
139 | 143 |
}, |
140 |
- moveResetPswd() { |
|
144 |
+ moveResetPswd() { |
|
141 | 145 |
this.$router.push({ |
142 | 146 |
path: "/resetPswd.page", |
143 | 147 |
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?