hmkim 06-04
250604 김혜민 소셜 중복로그인 에러 수정
@70581945710691ba939a6cf7f5b456f38e5f20a5
client/resources/api/index.js
--- client/resources/api/index.js
+++ client/resources/api/index.js
@@ -1,12 +1,12 @@
 import axios from 'axios';
-// import store from "../../views/pages/AppStore";
 import { getGlobalStore } from '../../views/pages/AppStore';
 
 const apiClient = axios.create({
   baseURL: '/',
   headers: {
     'Content-Type': 'application/json; charset=UTF-8',
-  }
+  },
+  withCredentials: true // 세션 쿠키를 위해 추가
 });
 
 const excludeCtxUrls = [
@@ -15,15 +15,21 @@
 
 apiClient.interceptors.request.use(
   config => {
-    const store = getGlobalStore(); // 전역 스토어 가져오기
+    const store = getGlobalStore();
     const excludeCtxUrl = excludeCtxUrls.some(url => config.url.includes(url));
     const contextPath = store?.state.contextPath || '';
-    console.log("Context Path:", contextPath);
+    const loginMode = store?.state.loginMode || 'J'; // 기본값은 JWT 모드
     if(!excludeCtxUrl) {
-      config.url = contextPath + config.url; // 요청 시 Context Path 추가
+      config.url = contextPath + config.url;
     }
 
-    config.headers.Authorization = store?.state.authorization; // 요청 시 AccessToken 추가
+    // 로그인 모드에 따른 헤더 설정
+     if (loginMode === 'J') {
+      config.headers.Authorization = store?.state.authorization;
+    } else if (loginMode === 'S') {
+      delete config.headers.Authorization;
+      config.withCredentials = true;
+    }
     return config;
   },
   error => {
@@ -32,7 +38,6 @@
 )
 
 apiClient.interceptors.response.use(
-  
   response => {
     return response;
   },
@@ -40,22 +45,36 @@
     if (!error.response) {
       return Promise.reject(error);
     }
+    
     if (error.response.status == 403 && error.response.data.message == '접근 권한이 없습니다.') {
       window.history.back();
     }
+    
     const originalReq = error.config;
+    const store = getGlobalStore();
+    const loginMode = store?.state.loginMode || 'J';
+    
     if (originalReq.url.includes('/refresh/tokenReissue.json')) {
       return Promise.reject(error);
     }
-    // 토큰의 만료기간이 끝난경우
-    //  if (error.response.status == 401 && error.response.data.message == 'Token expired' && !originalReq._retry) {
-    if (error.response.status === 401 && error.response.data?.message?.toLowerCase().includes('expired') && !originalReq._retry) {
-      const store = getGlobalStore(); // 전역 스토어 가져오기
-        originalReq._retry = true; // 재요청 시도(한번만 실행)
+    
+    // 핵심: 401 에러 처리를 로그인 모드별로 분기
+    if (error.response.status === 401 && 
+        error.response.data?.message?.toLowerCase().includes('expired') && 
+        !originalReq._retry) {
+      
+      originalReq._retry = true;
+      
+      if (loginMode === 'J') {
+        // JWT 모드: 기존 토큰 재발급 로직
         try {
-          const res = await axios.post('/refresh/tokenReissue.json', {});
-          store.commit('setAuthorization', res.headers.authorization); // 새로 발급 받은 AccessToken 저장
-          originalReq.headers.Authorization = store.state.authorization; // 새로 발급 받은 AccessToken을 기존 요청에 추가
+          const res = await axios.post('/refresh/tokenReissue.json', {}, {
+            withCredentials: true
+          });
+          
+          store.commit('setAuthorization', res.headers.authorization);
+          originalReq.headers.Authorization = store.state.authorization;
+          
           /** jwt토큰 디코딩 **/
           const base64String = store.state.authorization.split('.')[1];
           const base64 = base64String.replace(/-/g, '+').replace(/_/g, '/');
@@ -63,22 +82,39 @@
             return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
           }).join(''));
           const mbr = JSON.parse(jsonPayload);
-          // const mbr = JSON.parse(decodeURIComponent(escape(window.atob(base64String)))); // jwt claim 추출
+          
           store.commit("setMbrNm", mbr.mbrNm);
           store.commit('setRoles', mbr.roles);
-          /** jwt토큰 디코딩 **/
-          return apiClient(originalReq); // 원래 요청 재시도 /pathname + search
+          /** jwt토큰 디코딩 끝 **/
+          
+          return apiClient(originalReq);
         } catch (refreshError) {
-          const redirect = window.location.pathname + window.location.search;
-          sessionStorage.setItem("redirect", redirect);
-          alert('세션이 종료 되었습니다.\n로그인을 새로 해주세요.');
-          store.commit("setStoreReset");
-          window.location = '/login.page';
+          handleSessionExpired(store);
           return Promise.reject(refreshError);
         }
+      } else if (loginMode === 'S') {
+        // 세션 모드: 토큰 재발급 시도하지 않고 바로 로그인 페이지로
+        handleSessionExpired(store, '세션이 만료되었습니다.');
+        return Promise.reject(error);
       }
+    }
+    
     return Promise.reject(error);
   }
 )
 
+// 세션 만료 처리 함수
+function handleSessionExpired(store, message = '세션이 종료되었습니다.') {
+  const redirect = window.location.pathname + window.location.search;
+  sessionStorage.setItem("redirect", redirect);
+  alert(`${message}\n로그인을 새로 해주세요.`);
+  store.commit("setStoreReset");
+  
+  const admPath = store.state.path?.includes("/adm");
+  const contextPath = store.state.contextPath || '';
+  const loginUrl = admPath ? contextPath + "/cmslogin.page" : contextPath + "/login.page";
+  
+  window.location = loginUrl;
+}
+
 export default apiClient;
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/AppRouter.js
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
@@ -179,13 +179,21 @@
     return;
   }
 
-  // 로그인 모드 확인 개선
-  let loginMode = store.state.loginMode || localStorage.getItem('loginMode') || 'J'; // 기본값으로 JWT 설정
+  // 로그인 모드 확인 
+  let loginMode = store.state.loginMode;
   
   // 로그인 모드가 여전히 없으면 localStorage에서 다시 한번 확인
-  if (!loginMode || loginMode === 'undefined') {
-    loginMode = 'J';
-  }
+   if (!loginMode || loginMode === 'undefined') {
+      // 스토어에 없으면 localStorage 확인
+      loginMode = localStorage.getItem('loginMode') || sessionStorage.getItem('loginMode');
+    }
+    if (!loginMode || loginMode === 'undefined') {
+      // 여전히 없으면 기본값 설정
+      loginMode = 'J';
+    }
+     if (store.state.loginMode !== loginMode) {
+      store.commit('setLoginMode', loginMode);
+    }
 
   // 로그인 상태 확인 개선
   let isLogin = false;
@@ -194,9 +202,10 @@
     const token = store.state.authorization || localStorage.getItem('authorization');
     isLogin = !!token;
   } else if (loginMode === 'S') {
-    // 세션 모드: mbrId 확인
-    const mbrId = store.state.mbrId || localStorage.getItem('mbrId');
-    isLogin = !!mbrId;
+    // 세션 모드: mbrId 또는 mbrNm 확인
+    const mbrId = store.state.mbrId || localStorage.getItem('mbrId') || sessionStorage.getItem('mbrId');
+    const mbrNm = store.state.mbrNm || localStorage.getItem('mbrNm') || sessionStorage.getItem('mbrNm');
+    isLogin = !!(mbrId || mbrNm);
   }
 
   // OAuth2 콜백 처리 - 로그인 페이지에서만 처리
client/views/pages/AppStore.js
--- client/views/pages/AppStore.js
+++ client/views/pages/AppStore.js
@@ -17,13 +17,11 @@
 export default function createAppStore(ctx, strgMode, lgnMode) {
   const store = createStore({
     plugins: [createPersistedState({
-      // storage: window.sessionStorage,
       storage: strgMode === 'S' ? window.sessionStorage : window.localStorage,
       paths: ['loginMode', 'authorization', 'mbrId', 'mbrNm', 'roles', 'contextPath', 'pageAuth']
     })],
     state: {
       authorization: null,
-      // refresh: null,
       loginMode: lgnMode || 'J',
       userType: "portal",
       menu: null,
@@ -34,18 +32,23 @@
     },
     getters: {
       getAuthorization: function () {},
-      // getRefresh: function () {},
       getMbrNm: function () {},
       getRoles: function () {},
       getLoginMode: state => state.loginMode,
+      // 로그인 상태 확인
+      isLoggedIn: (state) => {
+        if (state.loginMode === 'J') {
+          return !!state.authorization && !!state.mbrNm;
+        } else if (state.loginMode === 'S') {
+          return !!state.mbrNm; 
+        }
+        return false;
+      },
     },
     mutations: {
       setAuthorization(state, newValue) {
         state.authorization = newValue;
       },
-      // setRefresh(state, newValue) {
-      //   state.refresh = newValue;
-      // },
       setMbrNm(state, newValue) {
         state.mbrNm = newValue;
       },
@@ -66,7 +69,6 @@
       },
       setStoreReset(state) {
         state.authorization = null;
-        // state.refresh = null;
         state.loginMode = 'J';
         state.mbrNm = null;
         state.mbrId = null;
@@ -102,12 +104,29 @@
       setLoginMode(state, value) {
         state.loginMode = value;
       },
+      // 로그인 정보 일괄 설정
+      setLoginInfo(state, { mbrNm, mbrId, roles, authorization, loginMode }) {
+        state.mbrNm = mbrNm;
+        state.mbrId = mbrId;
+        state.roles = roles || [{authority: "ROLE_NONE"}];
+        
+        if (loginMode) {
+          state.loginMode = loginMode;
+        }
+        
+        // JWT 모드일 때만 authorization 저장
+        if (state.loginMode === 'J' && authorization) {
+          state.authorization = authorization;
+        } else if (state.loginMode === 'S') {
+          state.authorization = null; // 세션 모드에서는 토큰 불필요
+        }
+      },
     },
     actions: {
       async logout({ commit }) {
         try {
-          const ctx = this.state.contextPath; // 캐시 초기화 전 contextPath 저장
-          const admPath = this.state.path?.includes("/adm") // 캐시 초기화 전 경로 구분 (true: 관리자 페이지, false: 사용자 페이지)
+          const ctx = this.state.contextPath;
+          const admPath = this.state.path?.includes("/adm")
           const loginMode = this.state.loginMode || localStorage.getItem('loginMode') || 'J'; 
           
           // 로그인 모드에 따른 처리
@@ -136,9 +155,9 @@
             'refresh', 
             'Authorization', 
             'JSESSIONID', 
-            'oauth_access_token',  // OAuth 토큰 쿠키
-            'oauth_refresh_token', // OAuth 리프레시 토큰
-            'SESSION'              // 스프링 기본 세션 쿠키
+            'oauth_access_token',
+            'oauth_refresh_token',
+            'SESSION'
           ];
           
           cookiesToDelete.forEach(cookieName => {
@@ -146,12 +165,11 @@
             document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname};`;
           });
           
-          // 4. 로그인 페이지로 이동 (OAuth 관련 파라미터 제거)
+          // 4. 로그인 페이지로 이동
           const cleanUrl = admPath ? 
             ctx + "/cmslogin.page" : 
             ctx + "/login.page";
             
-          // URL에서 OAuth 관련 파라미터 제거
           window.history.replaceState({}, document.title, cleanUrl);
           window.location.href = cleanUrl;
           
@@ -166,7 +184,6 @@
           const ctx = this.state.contextPath;
           const admPath = this.state.path?.includes("/adm");
           
-          // 에러 메시지 표시
           const errorData = error.response?.data;
           if (errorData?.message) {
             alert(errorData.message);
@@ -174,7 +191,6 @@
             console.log("로그아웃 처리 중 예상치 못한 오류 발생");
           }
           
-          // 로그인 페이지로 이동
           const cleanUrl = admPath ? 
             ctx + "/cmslogin.page" : 
             ctx + "/login.page";
@@ -200,7 +216,7 @@
     },
   });
 
-  setGlobalStore(store); // 전역 스토어 설정
+  setGlobalStore(store);
 
   return store;
 }
(파일 끝에 줄바꿈 문자 없음)
client/views/pages/login/AdminLogin.vue
--- client/views/pages/login/AdminLogin.vue
+++ client/views/pages/login/AdminLogin.vue
@@ -185,7 +185,7 @@
 
         // 로그인 성공 시
         async loginSuccessProc(res) {
-            const loginType = res.headers['login-type']; // 세션/토큰 로그인 구분
+            const loginType = res.headers['loginmode']; // 세션/토큰 로그인 구분
             this.storageType = res.headers['storage-type']; // 로컬 스토리지 타입 (세션/로컬)
             if (loginType === 'J') {
                 this.handleJWTLogin(res);
client/views/pages/login/Login.vue
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
@@ -155,7 +155,9 @@
     },
 
     async loginSuccessProc(res) {
-      const loginType = res.headers['login-type'];
+      console.log('login success :: res? = ' , res);
+      const loginType = res.headers['loginmode'];
+      console.log('loginType  :  ', loginType);
       if (loginType === 'J') {
         this.handleJWTLogin(res);
       } else if (loginType === 'S') {
Add a comment
List