

250616 김혜민 로그인 방식 코드 정리
@e64741bed33636ef8ec5c763f7afaef32bad5903
--- client/views/index.js
+++ client/views/index.js
... | ... | @@ -27,15 +27,7 @@ |
27 | 27 |
const lgnMode = await loginMode(); |
28 | 28 |
|
29 | 29 |
const store = createAppStore(ctx, strgMode, lgnMode); |
30 |
- |
|
31 |
- // const savedLoginMode = localStorage.getItem("loginMode"); |
|
32 |
- // const savedLoginMode = JSON.parse(localStorage.getItem("vuex"))?.loginMode; |
|
33 |
- // console.log("Saved Login Mode:", savedLoginMode); |
|
34 |
- // if (savedLoginMode) { |
|
35 |
- // console.log("Store loginMode:", store.state.loginMode); |
|
36 |
- // // store.commit("setLoginMode", savedLoginMode); |
|
37 |
- // } |
|
38 |
- |
|
30 |
+ |
|
39 | 31 |
const router = await createAppRouter() |
40 | 32 |
const vue = createApp(App) |
41 | 33 |
.use(router) |
--- client/views/pages/AppStore.js
+++ client/views/pages/AppStore.js
... | ... | @@ -18,11 +18,21 @@ |
18 | 18 |
const store = createStore({ |
19 | 19 |
plugins: [createPersistedState({ |
20 | 20 |
storage: strgMode === 'S' ? window.sessionStorage : window.localStorage, |
21 |
- paths: ['loginMode', 'authorization', 'mbrId', 'mbrNm', 'roles', 'contextPath', 'pageAuth'] |
|
21 |
+ paths: [ |
|
22 |
+ 'loginMode', // J, S |
|
23 |
+ 'policyMode', // Y, N |
|
24 |
+ 'authorization', |
|
25 |
+ 'mbrId', |
|
26 |
+ 'mbrNm', |
|
27 |
+ 'roles', |
|
28 |
+ 'contextPath', |
|
29 |
+ 'pageAuth' |
|
30 |
+ ] |
|
22 | 31 |
})], |
23 | 32 |
state: { |
24 | 33 |
authorization: null, |
25 |
- loginMode: lgnMode || 'J', |
|
34 |
+ loginMode: lgnMode || 'J', // J, S |
|
35 |
+ policyMode: 'Y', // Y, N (기본값: 허용) |
|
26 | 36 |
userType: "portal", |
27 | 37 |
menu: null, |
28 | 38 |
path: null, |
... | ... | @@ -35,6 +45,7 @@ |
35 | 45 |
getMbrNm: function () {}, |
36 | 46 |
getRoles: function () {}, |
37 | 47 |
getLoginMode: state => state.loginMode, |
48 |
+ getPolicyMode: state => state.policyMode, |
|
38 | 49 |
// 로그인 상태 확인 |
39 | 50 |
isLoggedIn: (state) => { |
40 | 51 |
if (state.loginMode === 'J') { |
... | ... | @@ -70,6 +81,7 @@ |
70 | 81 |
setStoreReset(state) { |
71 | 82 |
state.authorization = null; |
72 | 83 |
state.loginMode = 'J'; |
84 |
+ state.policyMode = 'Y'; |
|
73 | 85 |
state.mbrNm = null; |
74 | 86 |
state.mbrId = null; |
75 | 87 |
state.roles = [{authority: "ROLE_NONE"}]; |
... | ... | @@ -101,17 +113,25 @@ |
101 | 113 |
setContextPath(state, ctx) { |
102 | 114 |
state.contextPath = ctx; |
103 | 115 |
}, |
116 |
+ |
|
104 | 117 |
setLoginMode(state, value) { |
105 | 118 |
state.loginMode = value; |
106 | 119 |
}, |
120 |
+ setPolicyMode(state, value) { |
|
121 |
+ state.policyMode = value; |
|
122 |
+ }, |
|
107 | 123 |
// 로그인 정보 일괄 설정 |
108 |
- setLoginInfo(state, { mbrNm, mbrId, roles, authorization, loginMode }) { |
|
124 |
+ setLoginInfo(state, { mbrNm, mbrId, roles, authorization, loginMode, policyMode }) { |
|
109 | 125 |
state.mbrNm = mbrNm; |
110 | 126 |
state.mbrId = mbrId; |
111 | 127 |
state.roles = roles || [{authority: "ROLE_NONE"}]; |
112 | 128 |
|
113 | 129 |
if (loginMode) { |
114 | 130 |
state.loginMode = loginMode; |
131 |
+ } |
|
132 |
+ |
|
133 |
+ if (policyMode) { |
|
134 |
+ state.policyMode = policyMode; |
|
115 | 135 |
} |
116 | 136 |
|
117 | 137 |
// JWT 모드일 때만 authorization 저장 |
... | ... | @@ -124,164 +144,37 @@ |
124 | 144 |
}, |
125 | 145 |
actions: { |
126 | 146 |
async logout({ commit, state, dispatch }) { |
127 |
- |
|
128 | 147 |
const ctx = state.contextPath; |
129 | 148 |
const admPath = state.path?.includes("/adm"); |
130 |
- const loginMode = state.loginMode || localStorage.getItem('loginMode') || 'J'; |
|
131 | 149 |
|
132 | 150 |
try { |
133 |
- // 1. 서버 로그아웃 API 호출 (모든 모드에서 호출) |
|
134 |
- const res = await logOutProc(); |
|
135 |
- // 2. 클라이언트 완전 정리 |
|
136 |
- await dispatch('performCompleteCleanup', { loginMode, ctx, admPath }); |
|
137 |
- } catch (error) { |
|
138 |
- // 오류 발생해도 클라이언트 정리는 수행 |
|
139 |
- await dispatch('performCompleteCleanup', { loginMode, ctx, admPath }); |
|
140 |
- } |
|
141 |
- }, |
|
142 |
- |
|
143 |
- // 완전한 클라이언트 정리 수행 |
|
144 |
- async performCompleteCleanup({ commit, dispatch }, { loginMode, ctx, admPath }) { |
|
145 |
- try { |
|
146 |
- // 1. 상태 초기화 |
|
147 |
- commit("setStoreReset"); |
|
148 |
- // 2. 모든 저장소 완전 정리 |
|
149 |
- dispatch('clearAllStorages'); |
|
150 |
- // 3. 모든 쿠키 제거 |
|
151 |
- dispatch('clearAllCookies'); |
|
152 |
- // 4. 세션 무효화 (세션 모드인 경우) |
|
153 |
- if (loginMode === 'S') { |
|
154 |
- dispatch('invalidateSession'); |
|
151 |
+ const res = await logOutProc(); |
|
152 |
+ |
|
153 |
+ if (res.status == 200) { |
|
154 |
+ commit("setStoreReset"); |
|
155 |
+ |
|
156 |
+ localStorage.clear(); |
|
157 |
+ sessionStorage.clear(); |
|
158 |
+ |
|
159 |
+ // 페이지 이동 |
|
160 |
+ const loginUrl = admPath ? |
|
161 |
+ (ctx || '') + "/cmslogin.page" : |
|
162 |
+ (ctx || '') + "/login.page"; |
|
163 |
+ |
|
164 |
+ window.location.href = loginUrl; |
|
155 | 165 |
} |
156 |
- // 5. 브라우저 캐시 정리 |
|
157 |
- dispatch('clearBrowserCache'); |
|
158 |
- // 6. 페이지 리다이렉트 |
|
166 |
+ } catch(error) { |
|
167 |
+ commit("setStoreReset"); |
|
168 |
+ localStorage.clear(); |
|
169 |
+ sessionStorage.clear(); |
|
170 |
+ |
|
159 | 171 |
const loginUrl = admPath ? |
160 | 172 |
(ctx || '') + "/cmslogin.page" : |
161 | 173 |
(ctx || '') + "/login.page"; |
162 |
- // 히스토리 정리 후 이동 |
|
163 |
- window.history.replaceState(null, '', loginUrl); |
|
174 |
+ |
|
164 | 175 |
window.location.href = loginUrl; |
165 |
- } catch (cleanupError) { |
|
166 |
- // 최종 수단: 강제 새로고침 |
|
167 |
- window.location.reload(); |
|
168 | 176 |
} |
169 | 177 |
}, |
170 |
- |
|
171 |
- // 모든 저장소 정리 |
|
172 |
- clearAllStorages() { |
|
173 |
- // localStorage 완전 정리 |
|
174 |
- const localStorageKeys = Object.keys(localStorage); |
|
175 |
- localStorageKeys.forEach(key => { |
|
176 |
- localStorage.removeItem(key); |
|
177 |
- }); |
|
178 |
- localStorage.clear(); |
|
179 |
- |
|
180 |
- // sessionStorage 완전 정리 |
|
181 |
- const sessionStorageKeys = Object.keys(sessionStorage); |
|
182 |
- sessionStorageKeys.forEach(key => { |
|
183 |
- sessionStorage.removeItem(key); |
|
184 |
- }); |
|
185 |
- sessionStorage.clear(); |
|
186 |
- }, |
|
187 |
- |
|
188 |
- // 모든 쿠키 제거 |
|
189 |
- clearAllCookies() { |
|
190 |
- const cookiesToDelete = [ |
|
191 |
- // 일반 인증 쿠키 |
|
192 |
- 'refresh', |
|
193 |
- 'Authorization', |
|
194 |
- 'access_token', |
|
195 |
- 'JSESSIONID', |
|
196 |
- 'SESSION', |
|
197 |
- |
|
198 |
- // OAuth 관련 쿠키 |
|
199 |
- 'oauth_access_token', |
|
200 |
- 'oauth_refresh_token', |
|
201 |
- 'oauth_state', |
|
202 |
- 'OAUTH2_AUTHORIZATION_REQUEST', |
|
203 |
- 'oauth2_auth_request', |
|
204 |
- |
|
205 |
- // 카카오 관련 |
|
206 |
- 'kakao_login', |
|
207 |
- '_kadu', |
|
208 |
- '_kadub', |
|
209 |
- '_kalt', |
|
210 |
- |
|
211 |
- // 네이버 관련 |
|
212 |
- 'NID_AUT', |
|
213 |
- 'NID_SES', |
|
214 |
- 'NID_JKL', |
|
215 |
- |
|
216 |
- // 구글 관련 |
|
217 |
- 'SACSID', |
|
218 |
- 'APISID', |
|
219 |
- 'SSID', |
|
220 |
- '1P_JAR', |
|
221 |
- |
|
222 |
- // 기타 가능한 쿠키 |
|
223 |
- 'remember-me', |
|
224 |
- 'user-session', |
|
225 |
- 'auth-token' |
|
226 |
- ]; |
|
227 |
- |
|
228 |
- const domains = [ |
|
229 |
- '', |
|
230 |
- '.' + window.location.hostname, |
|
231 |
- window.location.hostname, |
|
232 |
- '.localhost', |
|
233 |
- 'localhost' |
|
234 |
- ]; |
|
235 |
- |
|
236 |
- const paths = ['/', '/oauth2', '/login', '/auth']; |
|
237 |
- |
|
238 |
- cookiesToDelete.forEach(cookieName => { |
|
239 |
- paths.forEach(path => { |
|
240 |
- domains.forEach(domain => { |
|
241 |
- // 기본 쿠키 삭제 |
|
242 |
- document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path};`; |
|
243 |
- |
|
244 |
- // 도메인별 쿠키 삭제 |
|
245 |
- if (domain) { |
|
246 |
- document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; domain=${domain};`; |
|
247 |
- } |
|
248 |
- }); |
|
249 |
- }); |
|
250 |
- }); |
|
251 |
- }, |
|
252 |
- |
|
253 |
- // 세션 무효화 |
|
254 |
- invalidateSession() { |
|
255 |
- // 세션 무효화를 위한 더미 요청 (필요한 경우) |
|
256 |
- fetch('/mbr/sessionInvalidate', { |
|
257 |
- method: 'POST', |
|
258 |
- credentials: 'include' |
|
259 |
- }).catch(() => {}); // 실패해도 무시 |
|
260 |
- }, |
|
261 |
- |
|
262 |
- // 브라우저 캐시 정리 |
|
263 |
- clearBrowserCache() { |
|
264 |
- // 캐시 API 지원 확인 및 정리 |
|
265 |
- if ('caches' in window) { |
|
266 |
- caches.keys().then(cacheNames => { |
|
267 |
- cacheNames.forEach(cacheName => { |
|
268 |
- caches.delete(cacheName); |
|
269 |
- }); |
|
270 |
- }).catch(() => {}); |
|
271 |
- } |
|
272 |
- |
|
273 |
- // IndexedDB 정리 (가능한 경우) |
|
274 |
- if ('indexedDB' in window) { |
|
275 |
- // 일반적인 DB 이름들 정리 시도 |
|
276 |
- const commonDBNames = ['auth_db', 'user_db', 'session_db']; |
|
277 |
- commonDBNames.forEach(dbName => { |
|
278 |
- try { |
|
279 |
- indexedDB.deleteDatabase(dbName); |
|
280 |
- } catch (e) {} |
|
281 |
- }); |
|
282 |
- } |
|
283 |
- }, |
|
284 |
- |
|
285 | 178 |
setUserType({ commit }, userType) { |
286 | 179 |
commit("setUserType", userType); |
287 | 180 |
}, |
--- client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
... | ... | @@ -158,10 +158,10 @@ |
158 | 158 |
} |
159 | 159 |
}, |
160 | 160 |
|
161 |
- // 중복로그인 설정 저장 - 개선된 버전 |
|
161 |
+ // 중복로그인 설정 저장 |
|
162 | 162 |
async saveByLoginPolicy() { |
163 | 163 |
const confirmed = confirm( |
164 |
- '로그인 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
|
164 |
+ '로그인 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
|
165 | 165 |
); |
166 | 166 |
if (!confirmed) { |
167 | 167 |
this.allowMultipleLogin = this.previousAllowMultipleLogin; |
... | ... | @@ -170,16 +170,14 @@ |
170 | 170 |
|
171 | 171 |
try { |
172 | 172 |
const loginPolicy = {}; |
173 |
- loginPolicy.mltLgnPrmYn = this.allowMultipleLogin; |
|
173 |
+ loginPolicy.allowMultipleLogin = this.allowMultipleLogin; |
|
174 | 174 |
await saveByLoginPolicy(loginPolicy); |
175 | 175 |
|
176 |
- // 전체 사용자 로그아웃 API 호출 |
|
177 | 176 |
await this.performGlobalLogout(); |
178 | 177 |
|
179 | 178 |
alert('중복 로그인 설정이 저장되었습니다.'); |
180 | 179 |
|
181 |
- // 완전한 정리 후 로그인 페이지로 이동 |
|
182 |
- await this.performCompleteCleanupAndRedirect(); |
|
180 |
+ this.simpleCleanupAndRedirect(); |
|
183 | 181 |
|
184 | 182 |
} catch (err) { |
185 | 183 |
alert('중복 로그인 설정 저장 실패: ' + (err.response?.data?.message || err.message)); |
... | ... | @@ -187,7 +185,7 @@ |
187 | 185 |
} |
188 | 186 |
}, |
189 | 187 |
|
190 |
- // 로그인 방식 저장 - 개선된 버전 |
|
188 |
+ // 로그인 방식 저장 |
|
191 | 189 |
async saveByLoginMode() { |
192 | 190 |
const confirmed = confirm( |
193 | 191 |
'로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
... | ... | @@ -202,13 +200,11 @@ |
202 | 200 |
loginMode.lgnMode = this.lgnMode; |
203 | 201 |
await saveByLoginMode(loginMode); |
204 | 202 |
|
205 |
- // 전체 사용자 로그아웃 API 호출 |
|
206 |
- await this.performGlobalLogout(); |
|
203 |
+ await this.performGlobalLogout(); |
|
207 | 204 |
|
208 | 205 |
alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
209 | 206 |
|
210 |
- // 완전한 정리 후 로그인 페이지로 이동 |
|
211 |
- await this.performCompleteCleanupAndRedirect(); |
|
207 |
+ this.simpleCleanupAndRedirect(); |
|
212 | 208 |
|
213 | 209 |
} catch (err) { |
214 | 210 |
alert('로그인 방식 저장 실패: ' + (err.response?.data?.message || err.message)); |
... | ... | @@ -216,7 +212,7 @@ |
216 | 212 |
} |
217 | 213 |
}, |
218 | 214 |
|
219 |
- // 스토리지 방식 저장 - 개선된 버전 |
|
215 |
+ // 스토리지 방식 저장 |
|
220 | 216 |
async saveByStorageMode() { |
221 | 217 |
const confirmed = confirm( |
222 | 218 |
'스토리지 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
... | ... | @@ -355,157 +351,38 @@ |
355 | 351 |
|
356 | 352 |
// 전체 사용자 로그아웃 API 호출 |
357 | 353 |
async performGlobalLogout() { |
358 |
- try { |
|
359 |
- console.log('전체 사용자 로그아웃 API 호출 시작'); |
|
360 |
- await fetch('/mbr/logoutAll.json', { |
|
361 |
- method: 'POST', |
|
362 |
- credentials: 'include', |
|
363 |
- headers: { |
|
364 |
- 'Content-Type': 'application/json' |
|
365 |
- } |
|
366 |
- }); |
|
367 |
- console.log('전체 사용자 로그아웃 API 호출 완료'); |
|
368 |
- } catch (error) { |
|
369 |
- console.warn('전체 로그아웃 API 호출 실패:', error); |
|
370 |
- // 실패해도 계속 진행 |
|
354 |
+ try { |
|
355 |
+ await fetch('/mbr/logoutAll.json', { |
|
356 |
+ method: 'POST', |
|
357 |
+ credentials: 'include', |
|
358 |
+ headers: { |
|
359 |
+ 'Content-Type': 'application/json' |
|
371 | 360 |
} |
361 |
+ }); |
|
362 |
+ } catch (error) { |
|
363 |
+ console.warn('전체 로그아웃 API 호출 실패:', error); |
|
364 |
+ } |
|
372 | 365 |
}, |
373 | 366 |
|
374 |
- // 완전한 정리 및 리다이렉트 |
|
375 | 367 |
async performCompleteCleanupAndRedirect(contextPath = null) { |
376 |
- try { |
|
377 |
- console.log('완전한 정리 시작'); |
|
368 |
+ try { |
|
378 | 369 |
|
379 |
- // 1. 스토어 완전 초기화 |
|
380 | 370 |
this.$store.commit("setStoreReset"); |
381 | 371 |
|
382 |
- // 2. 모든 저장소 정리 |
|
383 |
- this.clearAllStorages(); |
|
372 |
+ localStorage.clear(); |
|
373 |
+ sessionStorage.clear(); |
|
384 | 374 |
|
385 |
- // 3. 모든 쿠키 제거 (클라이언트 사이드) |
|
386 |
- this.clearAllClientCookies(); |
|
387 |
- |
|
388 |
- // 4. 브라우저 캐시 정리 |
|
389 |
- this.clearBrowserCache(); |
|
390 |
- |
|
391 |
- // 5. 페이지 이동 |
|
392 | 375 |
const targetPath = contextPath !== null ? |
393 | 376 |
`${contextPath}/cmslogin.page` : |
394 | 377 |
this.$filters.ctxPath('/cmslogin.page'); |
395 | 378 |
|
396 |
- console.log('리다이렉트 경로:', targetPath); |
|
397 |
- |
|
398 |
- // 히스토리 정리 후 이동 |
|
399 |
- window.history.replaceState(null, '', targetPath); |
|
400 | 379 |
window.location.href = targetPath; |
401 | 380 |
|
402 | 381 |
} catch (error) { |
403 |
- console.error('완전한 정리 중 오류:', error); |
|
404 |
- // 최종 수단: 강제 새로고침 |
|
382 |
+ console.error('정리 중 오류:', error); |
|
405 | 383 |
window.location.reload(); |
406 | 384 |
} |
407 | 385 |
}, |
408 |
- |
|
409 |
- // 모든 저장소 정리 |
|
410 |
- clearAllStorages() { |
|
411 |
- try { |
|
412 |
- console.log('저장소 정리 시작'); |
|
413 |
- |
|
414 |
- // localStorage 완전 정리 |
|
415 |
- const localStorageKeys = Object.keys(localStorage); |
|
416 |
- localStorageKeys.forEach(key => { |
|
417 |
- localStorage.removeItem(key); |
|
418 |
- }); |
|
419 |
- localStorage.clear(); |
|
420 |
- |
|
421 |
- // sessionStorage 완전 정리 |
|
422 |
- const sessionStorageKeys = Object.keys(sessionStorage); |
|
423 |
- sessionStorageKeys.forEach(key => { |
|
424 |
- sessionStorage.removeItem(key); |
|
425 |
- }); |
|
426 |
- sessionStorage.clear(); |
|
427 |
- |
|
428 |
- console.log('저장소 정리 완료'); |
|
429 |
- } catch (error) { |
|
430 |
- console.error('저장소 정리 실패:', error); |
|
431 |
- } |
|
432 |
- }, |
|
433 |
- |
|
434 |
- // 모든 클라이언트 쿠키 제거 |
|
435 |
- clearAllClientCookies() { |
|
436 |
- try { |
|
437 |
- console.log('클라이언트 쿠키 제거 시작'); |
|
438 |
- |
|
439 |
- const cookiesToDelete = [ |
|
440 |
- // 일반 인증 쿠키 |
|
441 |
- 'refresh', 'Authorization', 'access_token', 'JSESSIONID', 'SESSION', |
|
442 |
- |
|
443 |
- // OAuth 관련 쿠키 |
|
444 |
- 'oauth_access_token', 'oauth_refresh_token', 'oauth_state', |
|
445 |
- 'OAUTH2_AUTHORIZATION_REQUEST', 'oauth2_auth_request', |
|
446 |
- |
|
447 |
- // 소셜 로그인 쿠키들 |
|
448 |
- 'kakao_login', '_kadu', '_kadub', '_kalt', '_kawlt', '_kawltea', '_karmt', '_karmts', |
|
449 |
- 'NID_AUT', 'NID_SES', 'NID_JKL', 'NID_INF', 'NID_LOG', |
|
450 |
- 'SACSID', 'APISID', 'SSID', 'HSID', 'SID', '1P_JAR', |
|
451 |
- '__Secure-1PAPISID', '__Secure-1PSID', '__Secure-3PAPISID', '__Secure-3PSID', |
|
452 |
- |
|
453 |
- // 기타 |
|
454 |
- 'remember-me', 'user-session', 'auth-token', 'login-token', 'csrf-token' |
|
455 |
- ]; |
|
456 |
- |
|
457 |
- const domains = ['', '.' + window.location.hostname, window.location.hostname, '.localhost', 'localhost']; |
|
458 |
- const paths = ['/', '/oauth2', '/login', '/auth', '/api', '/mbr', '/admin']; |
|
459 |
- |
|
460 |
- cookiesToDelete.forEach(cookieName => { |
|
461 |
- paths.forEach(path => { |
|
462 |
- domains.forEach(domain => { |
|
463 |
- // 기본 쿠키 삭제 |
|
464 |
- document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path};`; |
|
465 |
- |
|
466 |
- // 도메인별 쿠키 삭제 |
|
467 |
- if (domain) { |
|
468 |
- document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; domain=${domain};`; |
|
469 |
- } |
|
470 |
- }); |
|
471 |
- }); |
|
472 |
- }); |
|
473 |
- |
|
474 |
- console.log('클라이언트 쿠키 제거 완료'); |
|
475 |
- } catch (error) { |
|
476 |
- console.error('클라이언트 쿠키 제거 실패:', error); |
|
477 |
- } |
|
478 |
- }, |
|
479 |
- |
|
480 |
- // 브라우저 캐시 정리 |
|
481 |
- clearBrowserCache() { |
|
482 |
- try { |
|
483 |
- console.log('브라우저 캐시 정리 시작'); |
|
484 |
- |
|
485 |
- // 캐시 API 지원 확인 및 정리 |
|
486 |
- if ('caches' in window) { |
|
487 |
- caches.keys().then(cacheNames => { |
|
488 |
- cacheNames.forEach(cacheName => { |
|
489 |
- caches.delete(cacheName); |
|
490 |
- }); |
|
491 |
- }).catch(() => {}); |
|
492 |
- } |
|
493 |
- |
|
494 |
- // IndexedDB 정리 (가능한 경우) |
|
495 |
- if ('indexedDB' in window) { |
|
496 |
- const commonDBNames = ['auth_db', 'user_db', 'session_db']; |
|
497 |
- commonDBNames.forEach(dbName => { |
|
498 |
- try { |
|
499 |
- indexedDB.deleteDatabase(dbName); |
|
500 |
- } catch (e) {} |
|
501 |
- }); |
|
502 |
- } |
|
503 |
- |
|
504 |
- console.log('브라우저 캐시 정리 완료'); |
|
505 |
- } catch (error) { |
|
506 |
- console.error('브라우저 캐시 정리 실패:', error); |
|
507 |
- } |
|
508 |
- } |
|
509 | 386 |
} |
510 | 387 |
} |
511 | 388 |
</script>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
... | ... | @@ -74,7 +74,7 @@ |
74 | 74 |
|
75 | 75 |
<script> |
76 | 76 |
import { useStore } from "vuex"; |
77 |
-import { loginProc, getUserInfo } from "../../../resources/api/login"; |
|
77 |
+import { loginProc, getUserInfo, oauthLogin } from "../../../resources/api/login"; |
|
78 | 78 |
import { check2ndAuthProc, sendAuthEmailProc } from "../../../resources/api/email"; |
79 | 79 |
import queryParams from "../../../resources/js/queryParams"; |
80 | 80 |
|
... | ... | @@ -98,14 +98,23 @@ |
98 | 98 |
}, |
99 | 99 |
|
100 | 100 |
async mounted() { |
101 |
- await this.$nextTick(); |
|
102 |
- // OAuth 파라미터가 있으면 콜백 처리 |
|
103 |
- if (this.hasOAuthParams()) { |
|
104 |
- console.log('OAuth 파라미터 감지, 콜백 처리 시작'); |
|
105 |
- await this.handleOAuthCallback(); |
|
106 |
- } |
|
107 |
- }, |
|
108 |
- |
|
101 |
+ await this.$nextTick(); |
|
102 |
+ console.log('URL:', window.location.href); |
|
103 |
+ |
|
104 |
+ const hasParams = window.location.search.includes('oauth_success') || |
|
105 |
+ window.location.search.includes('error'); |
|
106 |
+ console.log('hasOAuthParams:', hasParams); |
|
107 |
+ |
|
108 |
+ if (hasParams) { |
|
109 |
+ console.log('OAuth 콜백 실행 시작!'); |
|
110 |
+ try { |
|
111 |
+ await this.handleOAuthCallback(); |
|
112 |
+ console.log('OAuth 콜백 완료!'); |
|
113 |
+ } catch (error) { |
|
114 |
+ console.error('OAuth 콜백 에러:', error); |
|
115 |
+ } |
|
116 |
+ } |
|
117 |
+ }, |
|
109 | 118 |
beforeUnmount() { |
110 | 119 |
this.isOAuthLoading = false; |
111 | 120 |
}, |
... | ... | @@ -113,7 +122,6 @@ |
113 | 122 |
watch: { |
114 | 123 |
'$route'(to) { |
115 | 124 |
if (to.query.oauth_success || to.query.error) { |
116 |
- console.log('라우트 변경으로 OAuth 콜백 감지'); |
|
117 | 125 |
this.handleOAuthCallback(); |
118 | 126 |
} |
119 | 127 |
} |
... | ... | @@ -156,10 +164,15 @@ |
156 | 164 |
}, |
157 | 165 |
|
158 | 166 |
async loginSuccessProc(res) { |
159 |
- const loginType = res.headers['loginmode']; |
|
160 |
- if (loginType === 'J') { |
|
167 |
+ const loginMode = res.headers['loginmode']; // J, S |
|
168 |
+ const policyMode = res.headers['policymode']; // Y, N |
|
169 |
+ |
|
170 |
+ this.$store.commit("setLoginMode", loginMode || 'J'); |
|
171 |
+ this.$store.commit("setPolicyMode", policyMode || 'Y'); |
|
172 |
+ |
|
173 |
+ if (loginMode === 'J') { |
|
161 | 174 |
this.handleJWTLogin(res); |
162 |
- } else if (loginType === 'S') { |
|
175 |
+ } else if (loginMode === 'S') { |
|
163 | 176 |
this.handleSessionLogin(res); |
164 | 177 |
} else { |
165 | 178 |
alert("알 수 없는 로그인 방식입니다."); |
... | ... | @@ -235,7 +248,6 @@ |
235 | 248 |
|
236 | 249 |
// ========== OAuth2 로그인 ========== |
237 | 250 |
fnOAuthLogin(provider) { |
238 |
- console.log('OAuth 로그인 시작:', provider); |
|
239 | 251 |
this.isOAuthLoading = true; |
240 | 252 |
|
241 | 253 |
const redirectUrl = this.restoreRedirect("redirect") || this.$route.fullPath; |
... | ... | @@ -243,14 +255,11 @@ |
243 | 255 |
sessionStorage.setItem('oauth_provider', provider); |
244 | 256 |
sessionStorage.setItem('oauth_start_time', Date.now().toString()); |
245 | 257 |
|
246 |
- // OAuth 로그인 페이지로 이동 |
|
247 |
- window.location.href = `/oauth2/login?provider=${provider}`; |
|
258 |
+ oauthLogin(provider); |
|
248 | 259 |
}, |
249 | 260 |
|
250 | 261 |
async handleOAuthCallback() { |
251 |
- const { error, errorMessage, oauthSuccess, lgnMth } = this.parseOAuthParams(); |
|
252 |
- |
|
253 |
- |
|
262 |
+ const { error, errorMessage, oauthSuccess, loginMode, policyMode } = this.parseOAuthParams(); |
|
254 | 263 |
if (error) { |
255 | 264 |
this.handleOAuthError(error, errorMessage); |
256 | 265 |
return; |
... | ... | @@ -261,12 +270,11 @@ |
261 | 270 |
} |
262 | 271 |
|
263 | 272 |
try { |
264 |
- console.log('OAuth 성공 처리 시작'); |
|
265 |
- |
|
266 |
- // 기존 시스템 로그인 모드 따라가기 |
|
267 |
- const finalLoginMode = loginMode || this.$store.state.loginMode || localStorage.getItem('loginMode') || 'J'; |
|
273 |
+ const finalLoginMode = loginMode || this.$store.state.loginMode || 'J'; |
|
274 |
+ const finalPolicyMode = policyMode || this.$store.state.policyMode || 'Y'; |
|
268 | 275 |
|
269 | 276 |
this.$store.commit("setLoginMode", finalLoginMode); |
277 |
+ this.$store.commit("setPolicyMode", finalPolicyMode); |
|
270 | 278 |
|
271 | 279 |
if (finalLoginMode === 'J') { |
272 | 280 |
await this.handleOAuthJWT(); |
... | ... | @@ -291,7 +299,8 @@ |
291 | 299 |
error: urlParams.get('error') || routeQuery.error, |
292 | 300 |
errorMessage: urlParams.get('message') || routeQuery.message, |
293 | 301 |
oauthSuccess: urlParams.get('oauth_success') || routeQuery.oauth_success, |
294 |
- loginMode: urlParams.get('loginMode') || routeQuery.loginMode |
|
302 |
+ loginMode: urlParams.get('loginMode') || routeQuery.loginMode, // J, S |
|
303 |
+ policyMode: urlParams.get('policyMode') || routeQuery.policyMode // Y, N |
|
295 | 304 |
}; |
296 | 305 |
}, |
297 | 306 |
|
... | ... | @@ -319,7 +328,6 @@ |
319 | 328 |
credentials: 'include' |
320 | 329 |
}); |
321 | 330 |
|
322 |
- |
|
323 | 331 |
if (response.status === 200) { |
324 | 332 |
const result = await response.json(); |
325 | 333 |
|
... | ... | @@ -343,7 +351,6 @@ |
343 | 351 |
} |
344 | 352 |
|
345 | 353 |
} catch (error) { |
346 |
- console.error('OAuth JWT 처리 실패:', error); |
|
347 | 354 |
throw error; |
348 | 355 |
} |
349 | 356 |
}, |
... | ... | @@ -359,7 +366,6 @@ |
359 | 366 |
'Cache-Control': 'no-cache' |
360 | 367 |
} |
361 | 368 |
}); |
362 |
- |
|
363 | 369 |
|
364 | 370 |
if (!userInfoRes || userInfoRes.status !== 200) { |
365 | 371 |
throw new Error('세션 정보를 가져올 수 없습니다.'); |
... | ... | @@ -381,6 +387,7 @@ |
381 | 387 |
|
382 | 388 |
// ========== 공통 처리 ========== |
383 | 389 |
setAuthInfo(loginMode, token, userInfo) { |
390 |
+ |
|
384 | 391 |
// Store 설정 |
385 | 392 |
try { |
386 | 393 |
if (typeof this.$store !== 'undefined' && this.$store.commit) { |
... | ... | @@ -410,7 +417,6 @@ |
410 | 417 |
|
411 | 418 |
const targetPath = this.getValidRedirectPath(redirectUrl, isAdmin); |
412 | 419 |
|
413 |
- |
|
414 | 420 |
await this.$nextTick(); |
415 | 421 |
this.$router.push({ path: targetPath }); |
416 | 422 |
|
... | ... | @@ -438,13 +444,11 @@ |
438 | 444 |
|
439 | 445 |
// ========== 에러 처리 및 정리 ========== |
440 | 446 |
handleOAuthError(error, errorMessage) { |
441 |
- console.error('OAuth 에러 처리:', { error, errorMessage }); |
|
442 | 447 |
|
443 | 448 |
this.isOAuthLoading = false; |
444 | 449 |
this.cleanupOAuth(); |
445 | 450 |
|
446 | 451 |
const message = decodeURIComponent(errorMessage || error || 'OAuth 로그인에 실패했습니다.'); |
447 |
- alert(`소셜 로그인 실패: ${message}`); |
|
448 | 452 |
|
449 | 453 |
// 현재 페이지가 메인 페이지가 아니면 로그인 페이지로 이동 |
450 | 454 |
if (this.$route.path !== this.$filters.ctxPath("/")) { |
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?