hmkim 06-16
250616 김혜민 로그인 방식 코드 정리
@e64741bed33636ef8ec5c763f7afaef32bad5903
client/views/index.js
--- client/views/index.js
+++ client/views/index.js
@@ -27,15 +27,7 @@
   const lgnMode = await loginMode();
 
   const store = createAppStore(ctx, strgMode, lgnMode);
-
-  // const savedLoginMode = localStorage.getItem("loginMode");
-  // const savedLoginMode = JSON.parse(localStorage.getItem("vuex"))?.loginMode;
-  // console.log("Saved Login Mode:", savedLoginMode);
-  // if (savedLoginMode) {
-  //   console.log("Store loginMode:", store.state.loginMode);
-  //   // store.commit("setLoginMode", savedLoginMode);
-  // }
-
+  
   const router = await createAppRouter()
   const vue = createApp(App)
     .use(router)
client/views/pages/AppStore.js
--- client/views/pages/AppStore.js
+++ client/views/pages/AppStore.js
@@ -18,11 +18,21 @@
   const store = createStore({
     plugins: [createPersistedState({
       storage: strgMode === 'S' ? window.sessionStorage : window.localStorage,
-      paths: ['loginMode', 'authorization', 'mbrId', 'mbrNm', 'roles', 'contextPath', 'pageAuth']
+      paths: [
+        'loginMode',      // J, S
+        'policyMode',     // Y, N  
+        'authorization', 
+        'mbrId', 
+        'mbrNm', 
+        'roles', 
+        'contextPath', 
+        'pageAuth'
+      ]
     })],
     state: {
       authorization: null,
-      loginMode: lgnMode || 'J',
+      loginMode: lgnMode || 'J',        // J, S
+      policyMode: 'Y',                  // Y, N (기본값: 허용)
       userType: "portal",
       menu: null,
       path: null,
@@ -35,6 +45,7 @@
       getMbrNm: function () {},
       getRoles: function () {},
       getLoginMode: state => state.loginMode,
+      getPolicyMode: state => state.policyMode,
       // 로그인 상태 확인
       isLoggedIn: (state) => {
         if (state.loginMode === 'J') {
@@ -70,6 +81,7 @@
       setStoreReset(state) {
         state.authorization = null;
         state.loginMode = 'J';
+        state.policyMode = 'Y';
         state.mbrNm = null;
         state.mbrId = null;
         state.roles = [{authority: "ROLE_NONE"}];
@@ -101,17 +113,25 @@
       setContextPath(state, ctx) {
         state.contextPath = ctx;
       },
+	  
       setLoginMode(state, value) {
         state.loginMode = value;
       },
+      setPolicyMode(state, value) {
+        state.policyMode = value;
+      },
       // 로그인 정보 일괄 설정
-      setLoginInfo(state, { mbrNm, mbrId, roles, authorization, loginMode }) {
+      setLoginInfo(state, { mbrNm, mbrId, roles, authorization, loginMode, policyMode }) {
         state.mbrNm = mbrNm;
         state.mbrId = mbrId;
         state.roles = roles || [{authority: "ROLE_NONE"}];
         
         if (loginMode) {
           state.loginMode = loginMode;
+        }
+        
+        if (policyMode) {
+          state.policyMode = policyMode;
         }
         
         // JWT 모드일 때만 authorization 저장
@@ -124,164 +144,37 @@
     },
     actions: {
       async logout({ commit, state, dispatch }) {
-        
         const ctx = state.contextPath;
         const admPath = state.path?.includes("/adm");
-        const loginMode = state.loginMode || localStorage.getItem('loginMode') || 'J';
         
         try {
-          // 1. 서버 로그아웃 API 호출 (모든 모드에서 호출)
-            const res = await logOutProc();
-          // 2. 클라이언트 완전 정리
-          await dispatch('performCompleteCleanup', { loginMode, ctx, admPath });
-        } catch (error) {
-          // 오류 발생해도 클라이언트 정리는 수행
-          await dispatch('performCompleteCleanup', { loginMode, ctx, admPath });
-        }
-      },
-      
-      // 완전한 클라이언트 정리 수행
-      async performCompleteCleanup({ commit, dispatch }, { loginMode, ctx, admPath }) {
-        try {
-          // 1. 상태 초기화
-          commit("setStoreReset");
-          // 2. 모든 저장소 완전 정리
-          dispatch('clearAllStorages');
-          // 3. 모든 쿠키 제거
-          dispatch('clearAllCookies');
-          // 4. 세션 무효화 (세션 모드인 경우)
-          if (loginMode === 'S') {
-            dispatch('invalidateSession');
+          const res = await logOutProc();
+          
+          if (res.status == 200) {
+            commit("setStoreReset");
+            
+            localStorage.clear();
+            sessionStorage.clear();
+            
+            // 페이지 이동
+            const loginUrl = admPath ? 
+              (ctx || '') + "/cmslogin.page" : 
+              (ctx || '') + "/login.page";
+              
+            window.location.href = loginUrl;
           }
-          // 5. 브라우저 캐시 정리
-          dispatch('clearBrowserCache');
-          // 6. 페이지 리다이렉트
+        } catch(error) {
+          commit("setStoreReset");
+          localStorage.clear();
+          sessionStorage.clear();
+          
           const loginUrl = admPath ? 
             (ctx || '') + "/cmslogin.page" : 
             (ctx || '') + "/login.page";
-          // 히스토리 정리 후 이동
-          window.history.replaceState(null, '', loginUrl);
+            
           window.location.href = loginUrl;
-        } catch (cleanupError) {
-          // 최종 수단: 강제 새로고침
-          window.location.reload();
         }
       },
-      
-      // 모든 저장소 정리
-      clearAllStorages() {
-          // localStorage 완전 정리
-          const localStorageKeys = Object.keys(localStorage);
-          localStorageKeys.forEach(key => {
-            localStorage.removeItem(key);
-          });
-          localStorage.clear();
-          
-          // sessionStorage 완전 정리
-          const sessionStorageKeys = Object.keys(sessionStorage);
-          sessionStorageKeys.forEach(key => {
-            sessionStorage.removeItem(key);
-          });
-          sessionStorage.clear();
-      },
-      
-      // 모든 쿠키 제거
-      clearAllCookies() {
-          const cookiesToDelete = [
-            // 일반 인증 쿠키
-            'refresh', 
-            'Authorization', 
-            'access_token',
-            'JSESSIONID', 
-            'SESSION',
-            
-            // OAuth 관련 쿠키
-            'oauth_access_token',
-            'oauth_refresh_token',
-            'oauth_state',
-            'OAUTH2_AUTHORIZATION_REQUEST',
-            'oauth2_auth_request',
-            
-            // 카카오 관련
-            'kakao_login',
-            '_kadu',
-            '_kadub',
-            '_kalt',
-            
-            // 네이버 관련
-            'NID_AUT',
-            'NID_SES',
-            'NID_JKL',
-            
-            // 구글 관련
-            'SACSID',
-            'APISID',
-            'SSID',
-            '1P_JAR',
-            
-            // 기타 가능한 쿠키
-            'remember-me',
-            'user-session',
-            'auth-token'
-          ];
-          
-          const domains = [
-            '', 
-            '.' + window.location.hostname,
-            window.location.hostname,
-            '.localhost',
-            'localhost'
-          ];
-          
-          const paths = ['/', '/oauth2', '/login', '/auth'];
-          
-          cookiesToDelete.forEach(cookieName => {
-            paths.forEach(path => {
-              domains.forEach(domain => {
-                // 기본 쿠키 삭제
-                document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path};`;
-                
-                // 도메인별 쿠키 삭제
-                if (domain) {
-                  document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; domain=${domain};`;
-                }
-              });
-            });
-          });
-      },
-      
-      // 세션 무효화
-      invalidateSession() {
-          // 세션 무효화를 위한 더미 요청 (필요한 경우)
-          fetch('/mbr/sessionInvalidate', {
-            method: 'POST',
-            credentials: 'include'
-          }).catch(() => {}); // 실패해도 무시
-      },
-      
-      // 브라우저 캐시 정리
-      clearBrowserCache() {
-          // 캐시 API 지원 확인 및 정리
-          if ('caches' in window) {
-            caches.keys().then(cacheNames => {
-              cacheNames.forEach(cacheName => {
-                caches.delete(cacheName);
-              });
-            }).catch(() => {});
-          }
-          
-          // IndexedDB 정리 (가능한 경우)
-          if ('indexedDB' in window) {
-            // 일반적인 DB 이름들 정리 시도
-            const commonDBNames = ['auth_db', 'user_db', 'session_db'];
-            commonDBNames.forEach(dbName => {
-              try {
-                indexedDB.deleteDatabase(dbName);
-              } catch (e) {}
-            });
-          }
-      },
-
       setUserType({ commit }, userType) {
         commit("setUserType", userType);
       },
client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
--- client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
@@ -158,10 +158,10 @@
       }
     },
 
-    // 중복로그인 설정 저장 - 개선된 버전
+    // 중복로그인 설정 저장
     async saveByLoginPolicy() {
       const confirmed = confirm(
-        '로그인 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
+    '로그인 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
       );
       if (!confirmed) {
         this.allowMultipleLogin = this.previousAllowMultipleLogin;
@@ -170,16 +170,14 @@
 
       try {
         const loginPolicy = {};
-        loginPolicy.mltLgnPrmYn = this.allowMultipleLogin;
+        loginPolicy.allowMultipleLogin = this.allowMultipleLogin;
         await saveByLoginPolicy(loginPolicy);
         
-        // 전체 사용자 로그아웃 API 호출
         await this.performGlobalLogout();
         
         alert('중복 로그인 설정이 저장되었습니다.');
         
-        // 완전한 정리 후 로그인 페이지로 이동
-        await this.performCompleteCleanupAndRedirect();
+        this.simpleCleanupAndRedirect();
         
       } catch (err) {
         alert('중복 로그인 설정 저장 실패: ' + (err.response?.data?.message || err.message));
@@ -187,7 +185,7 @@
       }
     },
 
-    // 로그인 방식 저장 - 개선된 버전
+    // 로그인 방식 저장
     async saveByLoginMode() {
       const confirmed = confirm(
         '로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
@@ -202,13 +200,11 @@
         loginMode.lgnMode = this.lgnMode;
         await saveByLoginMode(loginMode);
         
-        // 전체 사용자 로그아웃 API 호출
-        await this.performGlobalLogout();  
+        await this.performGlobalLogout();
         
         alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.');
         
-        // 완전한 정리 후 로그인 페이지로 이동
-        await this.performCompleteCleanupAndRedirect();
+        this.simpleCleanupAndRedirect();
         
       } catch (err) {
         alert('로그인 방식 저장 실패: ' + (err.response?.data?.message || err.message));
@@ -216,7 +212,7 @@
       }
     },
 
-    // 스토리지 방식 저장 - 개선된 버전
+    // 스토리지 방식 저장
     async saveByStorageMode() {
       const confirmed = confirm(
         '스토리지 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
@@ -355,157 +351,38 @@
 
     // 전체 사용자 로그아웃 API 호출
     async performGlobalLogout() {
-      try {
-        console.log('전체 사용자 로그아웃 API 호출 시작');
-        await fetch('/mbr/logoutAll.json', {
-          method: 'POST',
-          credentials: 'include',
-          headers: {
-            'Content-Type': 'application/json'
-          }
-        });
-        console.log('전체 사용자 로그아웃 API 호출 완료');
-      } catch (error) {
-        console.warn('전체 로그아웃 API 호출 실패:', error);
-        // 실패해도 계속 진행
+     try {
+    await fetch('/mbr/logoutAll.json', {
+      method: 'POST',
+      credentials: 'include',
+      headers: {
+        'Content-Type': 'application/json'
       }
+    });
+  } catch (error) {
+    console.warn('전체 로그아웃 API 호출 실패:', error);
+  }
     },
 
-    // 완전한 정리 및 리다이렉트
     async performCompleteCleanupAndRedirect(contextPath = null) {
-      try {
-        console.log('완전한 정리 시작');
+       try {
         
-        // 1. 스토어 완전 초기화
         this.$store.commit("setStoreReset");
         
-        // 2. 모든 저장소 정리
-        this.clearAllStorages();
+        localStorage.clear();
+        sessionStorage.clear();
         
-        // 3. 모든 쿠키 제거 (클라이언트 사이드)
-        this.clearAllClientCookies();
-        
-        // 4. 브라우저 캐시 정리
-        this.clearBrowserCache();
-        
-        // 5. 페이지 이동
         const targetPath = contextPath !== null ? 
           `${contextPath}/cmslogin.page` : 
           this.$filters.ctxPath('/cmslogin.page');
         
-        console.log('리다이렉트 경로:', targetPath);
-        
-        // 히스토리 정리 후 이동
-        window.history.replaceState(null, '', targetPath);
         window.location.href = targetPath;
         
       } catch (error) {
-        console.error('완전한 정리 중 오류:', error);
-        // 최종 수단: 강제 새로고침
+        console.error('정리 중 오류:', error);
         window.location.reload();
       }
     },
-
-    // 모든 저장소 정리
-    clearAllStorages() {
-      try {
-        console.log('저장소 정리 시작');
-        
-        // localStorage 완전 정리
-        const localStorageKeys = Object.keys(localStorage);
-        localStorageKeys.forEach(key => {
-          localStorage.removeItem(key);
-        });
-        localStorage.clear();
-        
-        // sessionStorage 완전 정리
-        const sessionStorageKeys = Object.keys(sessionStorage);
-        sessionStorageKeys.forEach(key => {
-          sessionStorage.removeItem(key);
-        });
-        sessionStorage.clear();
-        
-        console.log('저장소 정리 완료');
-      } catch (error) {
-        console.error('저장소 정리 실패:', error);
-      }
-    },
-
-    // 모든 클라이언트 쿠키 제거
-    clearAllClientCookies() {
-      try {
-        console.log('클라이언트 쿠키 제거 시작');
-        
-        const cookiesToDelete = [
-          // 일반 인증 쿠키
-          'refresh', 'Authorization', 'access_token', 'JSESSIONID', 'SESSION',
-          
-          // OAuth 관련 쿠키
-          'oauth_access_token', 'oauth_refresh_token', 'oauth_state',
-          'OAUTH2_AUTHORIZATION_REQUEST', 'oauth2_auth_request',
-          
-          // 소셜 로그인 쿠키들
-          'kakao_login', '_kadu', '_kadub', '_kalt', '_kawlt', '_kawltea', '_karmt', '_karmts',
-          'NID_AUT', 'NID_SES', 'NID_JKL', 'NID_INF', 'NID_LOG',
-          'SACSID', 'APISID', 'SSID', 'HSID', 'SID', '1P_JAR',
-          '__Secure-1PAPISID', '__Secure-1PSID', '__Secure-3PAPISID', '__Secure-3PSID',
-          
-          // 기타
-          'remember-me', 'user-session', 'auth-token', 'login-token', 'csrf-token'
-        ];
-        
-        const domains = ['', '.' + window.location.hostname, window.location.hostname, '.localhost', 'localhost'];
-        const paths = ['/', '/oauth2', '/login', '/auth', '/api', '/mbr', '/admin'];
-        
-        cookiesToDelete.forEach(cookieName => {
-          paths.forEach(path => {
-            domains.forEach(domain => {
-              // 기본 쿠키 삭제
-              document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path};`;
-              
-              // 도메인별 쿠키 삭제
-              if (domain) {
-                document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; domain=${domain};`;
-              }
-            });
-          });
-        });
-        
-        console.log('클라이언트 쿠키 제거 완료');
-      } catch (error) {
-        console.error('클라이언트 쿠키 제거 실패:', error);
-      }
-    },
-
-    // 브라우저 캐시 정리
-    clearBrowserCache() {
-      try {
-        console.log('브라우저 캐시 정리 시작');
-        
-        // 캐시 API 지원 확인 및 정리
-        if ('caches' in window) {
-          caches.keys().then(cacheNames => {
-            cacheNames.forEach(cacheName => {
-              caches.delete(cacheName);
-            });
-          }).catch(() => {});
-        }
-        
-        // IndexedDB 정리 (가능한 경우)
-        if ('indexedDB' in window) {
-          const commonDBNames = ['auth_db', 'user_db', 'session_db'];
-          commonDBNames.forEach(dbName => {
-            try {
-              indexedDB.deleteDatabase(dbName);
-            } catch (e) {}
-          });
-        }
-        
-        console.log('브라우저 캐시 정리 완료');
-      } catch (error) {
-        console.error('브라우저 캐시 정리 실패:', error);
-      }
-    }
   }
 }
 </script>
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/login/Login.vue
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
@@ -74,7 +74,7 @@
 
 <script>
 import { useStore } from "vuex";
-import { loginProc, getUserInfo } from "../../../resources/api/login";
+import { loginProc, getUserInfo, oauthLogin } from "../../../resources/api/login";
 import { check2ndAuthProc, sendAuthEmailProc } from "../../../resources/api/email";
 import queryParams from "../../../resources/js/queryParams";
 
@@ -98,14 +98,23 @@
   },
 
   async mounted() {
-    await this.$nextTick();
-    // OAuth 파라미터가 있으면 콜백 처리
-    if (this.hasOAuthParams()) {
-      console.log('OAuth 파라미터 감지, 콜백 처리 시작');
-      await this.handleOAuthCallback();
-    }
-  },
-
+      await this.$nextTick();
+      console.log('URL:', window.location.href);
+      
+      const hasParams = window.location.search.includes('oauth_success') || 
+                      window.location.search.includes('error');
+      console.log('hasOAuthParams:', hasParams);
+      
+      if (hasParams) {
+          console.log('OAuth 콜백 실행 시작!');
+          try {
+              await this.handleOAuthCallback();
+              console.log('OAuth 콜백 완료!');
+          } catch (error) {
+              console.error('OAuth 콜백 에러:', error);
+          }
+        }
+    },
   beforeUnmount() {
     this.isOAuthLoading = false;
   },
@@ -113,7 +122,6 @@
   watch: {
     '$route'(to) {
       if (to.query.oauth_success || to.query.error) {
-        console.log('라우트 변경으로 OAuth 콜백 감지');
         this.handleOAuthCallback();
       }
     }
@@ -156,10 +164,15 @@
     },
 
     async loginSuccessProc(res) {
-      const loginType = res.headers['loginmode'];
-      if (loginType === 'J') {
+      const loginMode = res.headers['loginmode'];     // J, S
+      const policyMode = res.headers['policymode'];   // Y, N
+      
+      this.$store.commit("setLoginMode", loginMode || 'J');
+      this.$store.commit("setPolicyMode", policyMode || 'Y');
+      
+      if (loginMode === 'J') {
         this.handleJWTLogin(res);
-      } else if (loginType === 'S') {
+      } else if (loginMode === 'S') {
         this.handleSessionLogin(res);
       } else {
         alert("알 수 없는 로그인 방식입니다.");
@@ -235,7 +248,6 @@
 
     // ========== OAuth2 로그인 ==========
     fnOAuthLogin(provider) {
-      console.log('OAuth 로그인 시작:', provider);
       this.isOAuthLoading = true;
       
       const redirectUrl = this.restoreRedirect("redirect") || this.$route.fullPath;
@@ -243,14 +255,11 @@
       sessionStorage.setItem('oauth_provider', provider);
       sessionStorage.setItem('oauth_start_time', Date.now().toString());
       
-      // OAuth 로그인 페이지로 이동
-      window.location.href = `/oauth2/login?provider=${provider}`;
+      oauthLogin(provider);
     },
 
     async handleOAuthCallback() {
-      const { error, errorMessage, oauthSuccess, lgnMth } = this.parseOAuthParams();
-
-
+      const { error, errorMessage, oauthSuccess, loginMode, policyMode } = this.parseOAuthParams();
       if (error) {
         this.handleOAuthError(error, errorMessage);
         return;
@@ -261,12 +270,11 @@
       }
 
       try {
-        console.log('OAuth 성공 처리 시작');
-        
-        // 기존 시스템 로그인 모드 따라가기
-        const finalLoginMode = loginMode || this.$store.state.loginMode || localStorage.getItem('loginMode') || 'J';
+        const finalLoginMode = loginMode || this.$store.state.loginMode || 'J';
+        const finalPolicyMode = policyMode || this.$store.state.policyMode || 'Y';
         
         this.$store.commit("setLoginMode", finalLoginMode);
+        this.$store.commit("setPolicyMode", finalPolicyMode);
 
         if (finalLoginMode === 'J') {
           await this.handleOAuthJWT();
@@ -291,7 +299,8 @@
         error: urlParams.get('error') || routeQuery.error,
         errorMessage: urlParams.get('message') || routeQuery.message,
         oauthSuccess: urlParams.get('oauth_success') || routeQuery.oauth_success,
-        loginMode: urlParams.get('loginMode') || routeQuery.loginMode
+        loginMode: urlParams.get('loginMode') || routeQuery.loginMode,      // J, S
+        policyMode: urlParams.get('policyMode') || routeQuery.policyMode    // Y, N
       };
     },
 
@@ -319,7 +328,6 @@
           credentials: 'include'
         });
         
-        
         if (response.status === 200) {
           const result = await response.json();
           
@@ -343,7 +351,6 @@
         }
         
       } catch (error) {
-        console.error('OAuth JWT 처리 실패:', error);
         throw error;
       }
     },
@@ -359,7 +366,6 @@
             'Cache-Control': 'no-cache'
           }
         });
-        
         
         if (!userInfoRes || userInfoRes.status !== 200) {
           throw new Error('세션 정보를 가져올 수 없습니다.');
@@ -381,6 +387,7 @@
 
     // ========== 공통 처리 ==========
     setAuthInfo(loginMode, token, userInfo) {
+      
       // Store 설정
       try {
         if (typeof this.$store !== 'undefined' && this.$store.commit) {
@@ -410,7 +417,6 @@
 
       const targetPath = this.getValidRedirectPath(redirectUrl, isAdmin);
       
-      
       await this.$nextTick();
       this.$router.push({ path: targetPath });
 
@@ -438,13 +444,11 @@
 
     // ========== 에러 처리 및 정리 ==========
     handleOAuthError(error, errorMessage) {
-      console.error('OAuth 에러 처리:', { error, errorMessage });
       
       this.isOAuthLoading = false;
       this.cleanupOAuth();
 
       const message = decodeURIComponent(errorMessage || error || 'OAuth 로그인에 실패했습니다.');
-      alert(`소셜 로그인 실패: ${message}`);
 
       // 현재 페이지가 메인 페이지가 아니면 로그인 페이지로 이동
       if (this.$route.path !== this.$filters.ctxPath("/")) {
Add a comment
List