
--- client/resources/api/index.js
+++ client/resources/api/index.js
... | ... | @@ -1,5 +1,6 @@ |
1 | 1 |
import axios from 'axios'; |
2 |
-import store from "../../views/pages/AppStore"; |
|
2 |
+// import store from "../../views/pages/AppStore"; |
|
3 |
+import { getGlobalStore } from '../../views/pages/AppStore'; |
|
3 | 4 |
|
4 | 5 |
const apiClient = axios.create({ |
5 | 6 |
baseURL: '/', |
... | ... | @@ -14,13 +15,15 @@ |
14 | 15 |
|
15 | 16 |
apiClient.interceptors.request.use( |
16 | 17 |
config => { |
18 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
17 | 19 |
const excludeCtxUrl = excludeCtxUrls.some(url => config.url.includes(url)); |
18 |
- const contextPath = store.state.contextPath || ''; |
|
20 |
+ const contextPath = store?.state.contextPath || ''; |
|
21 |
+ console.log("Context Path:", contextPath); |
|
19 | 22 |
if(!excludeCtxUrl) { |
20 | 23 |
config.url = contextPath + config.url; // 요청 시 Context Path 추가 |
21 | 24 |
} |
22 | 25 |
|
23 |
- config.headers.Authorization = store.state.authorization; // 요청 시 AccessToken 추가 |
|
26 |
+ config.headers.Authorization = store?.state.authorization; // 요청 시 AccessToken 추가 |
|
24 | 27 |
return config; |
25 | 28 |
}, |
26 | 29 |
error => { |
... | ... | @@ -45,34 +48,35 @@ |
45 | 48 |
return Promise.reject(error); |
46 | 49 |
} |
47 | 50 |
// 토큰의 만료기간이 끝난경우 |
48 |
- // if (error.response.status == 401 && error.response.data.message == 'Token expired' && !originalReq._retry) { |
|
49 |
- if (error.response.status === 401 && error.response.data?.message?.toLowerCase().includes('expired') && !originalReq._retry) { |
|
50 |
- originalReq._retry = true; // 재요청 시도(한번만 실행) |
|
51 |
- try { |
|
52 |
- const res = await axios.post('/refresh/tokenReissue.json', {}); |
|
53 |
- store.commit('setAuthorization', res.headers.authorization); // 새로 발급 받은 AccessToken 저장 |
|
54 |
- originalReq.headers.Authorization = store.state.authorization; // 새로 발급 받은 AccessToken을 기존 요청에 추가 |
|
55 |
- /** jwt토큰 디코딩 **/ |
|
56 |
- const base64String = store.state.authorization.split('.')[1]; |
|
57 |
- const base64 = base64String.replace(/-/g, '+').replace(/_/g, '/'); |
|
58 |
- const jsonPayload = decodeURIComponent(atob(base64).split('').map(c => { |
|
59 |
- return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); |
|
60 |
- }).join('')); |
|
61 |
- const mbr = JSON.parse(jsonPayload); |
|
62 |
- // const mbr = JSON.parse(decodeURIComponent(escape(window.atob(base64String)))); // jwt claim 추출 |
|
63 |
- store.commit("setMbrNm", mbr.mbrNm); |
|
64 |
- store.commit('setRoles', mbr.roles); |
|
65 |
- /** jwt토큰 디코딩 **/ |
|
66 |
- return apiClient(originalReq); // 원래 요청 재시도 /pathname + search |
|
67 |
- } catch (refreshError) { |
|
68 |
- const redirect = window.location.pathname + window.location.search; |
|
69 |
- sessionStorage.setItem("redirect", redirect); |
|
70 |
- alert('세션이 종료 되었습니다.\n로그인을 새로 해주세요.'); |
|
71 |
- store.commit("setStoreReset"); |
|
72 |
- window.location = '/login.page'; |
|
73 |
- return Promise.reject(refreshError); |
|
51 |
+ // if (error.response.status == 401 && error.response.data.message == 'Token expired' && !originalReq._retry) { |
|
52 |
+ if (error.response.status === 401 && error.response.data?.message?.toLowerCase().includes('expired') && !originalReq._retry) { |
|
53 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
54 |
+ originalReq._retry = true; // 재요청 시도(한번만 실행) |
|
55 |
+ try { |
|
56 |
+ const res = await axios.post('/refresh/tokenReissue.json', {}); |
|
57 |
+ store.commit('setAuthorization', res.headers.authorization); // 새로 발급 받은 AccessToken 저장 |
|
58 |
+ originalReq.headers.Authorization = store.state.authorization; // 새로 발급 받은 AccessToken을 기존 요청에 추가 |
|
59 |
+ /** jwt토큰 디코딩 **/ |
|
60 |
+ const base64String = store.state.authorization.split('.')[1]; |
|
61 |
+ const base64 = base64String.replace(/-/g, '+').replace(/_/g, '/'); |
|
62 |
+ const jsonPayload = decodeURIComponent(atob(base64).split('').map(c => { |
|
63 |
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); |
|
64 |
+ }).join('')); |
|
65 |
+ const mbr = JSON.parse(jsonPayload); |
|
66 |
+ // const mbr = JSON.parse(decodeURIComponent(escape(window.atob(base64String)))); // jwt claim 추출 |
|
67 |
+ store.commit("setMbrNm", mbr.mbrNm); |
|
68 |
+ store.commit('setRoles', mbr.roles); |
|
69 |
+ /** jwt토큰 디코딩 **/ |
|
70 |
+ return apiClient(originalReq); // 원래 요청 재시도 /pathname + search |
|
71 |
+ } catch (refreshError) { |
|
72 |
+ const redirect = window.location.pathname + window.location.search; |
|
73 |
+ sessionStorage.setItem("redirect", redirect); |
|
74 |
+ alert('세션이 종료 되었습니다.\n로그인을 새로 해주세요.'); |
|
75 |
+ store.commit("setStoreReset"); |
|
76 |
+ window.location = '/login.page'; |
|
77 |
+ return Promise.reject(refreshError); |
|
78 |
+ } |
|
74 | 79 |
} |
75 |
- } |
|
76 | 80 |
return Promise.reject(error); |
77 | 81 |
} |
78 | 82 |
) |
--- client/resources/api/logOut.js
+++ client/resources/api/logOut.js
... | ... | @@ -1,7 +1,8 @@ |
1 | 1 |
import apiClient from "./index"; |
2 |
-import store from '../../views/pages/AppStore'; |
|
2 |
+import { getGlobalStore } from '../../views/pages/AppStore'; |
|
3 | 3 |
|
4 | 4 |
export const logOutProc = () => { |
5 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
5 | 6 |
return apiClient.post(`/mbr/logout.json`, {}, { |
6 | 7 |
headers: { |
7 | 8 |
'refresh': store.state.refresh |
--- client/resources/api/loginPolicy.js
+++ client/resources/api/loginPolicy.js
... | ... | @@ -22,4 +22,21 @@ |
22 | 22 |
|
23 | 23 |
export const saveBy2ndAuth = email2ndAuth => { |
24 | 24 |
return apiClient.post(`/admin/loginPolicy/saveEmail2ndAuth.json`, email2ndAuth); |
25 |
+} |
|
26 |
+ |
|
27 |
+export const findAllByStorageMode = () => { |
|
28 |
+ return apiClient.post(`/admin/loginPolicy/findByStorageMode.json`); |
|
29 |
+} |
|
30 |
+ |
|
31 |
+export const saveByStorageMode = storageMode => { |
|
32 |
+ return apiClient.post(`/admin/loginPolicy/saveStorageMode.json`, storageMode); |
|
33 |
+} |
|
34 |
+ |
|
35 |
+/** 초기 세팅용 */ |
|
36 |
+export const getLoginMode = () => { |
|
37 |
+ return apiClient.post(`/sys/loginPolicy/getLoginMode.json`); |
|
38 |
+} |
|
39 |
+ |
|
40 |
+export const getStorageMode = () => { |
|
41 |
+ return apiClient.post(`/sys/loginPolicy/findByStorageMode.json`); |
|
25 | 42 |
}(파일 끝에 줄바꿈 문자 없음) |
--- client/resources/js/commonPlugin.js
+++ client/resources/js/commonPlugin.js
... | ... | @@ -1,5 +1,5 @@ |
1 | 1 |
import { save } from "../../resources/api/cntnStats"; |
2 |
-import store from "../../views/pages/AppStore"; |
|
2 |
+import { getGlobalStore } from "../../views/pages/AppStore"; |
|
3 | 3 |
|
4 | 4 |
/** |
5 | 5 |
* 공통 처리 플러그인 |
... | ... | @@ -20,6 +20,7 @@ |
20 | 20 |
*/ |
21 | 21 |
|
22 | 22 |
async function cntnSave(data){ |
23 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
23 | 24 |
const isLogin = store.state.loginAt; // 로그인 유무 정보 확인 |
24 | 25 |
|
25 | 26 |
axios({ |
--- client/views/common/filters.js
+++ client/views/common/filters.js
... | ... | @@ -1,16 +1,17 @@ |
1 | 1 |
import moment from 'moment'; |
2 |
-import store from '../pages/AppStore'; |
|
2 |
+import { getGlobalStore } from '../pages/AppStore'; |
|
3 | 3 |
|
4 | 4 |
const filters = { |
5 |
- |
|
6 | 5 |
// Context Path를 포함한 URL 생성 |
7 | 6 |
ctxPath(path) { |
7 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
8 | 8 |
const contextPath = store.state.contextPath || ''; |
9 | 9 |
return contextPath + path; |
10 | 10 |
}, |
11 | 11 |
|
12 | 12 |
// Context Path를 제외한 URL 생성 |
13 | 13 |
logicalPath(path) { |
14 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
14 | 15 |
const contextPath = store.state.contextPath || ''; |
15 | 16 |
return (contextPath !== '' && path.startsWith(contextPath)) ? path.slice(contextPath.length) : path; |
16 | 17 |
}, |
--- client/views/index.js
+++ client/views/index.js
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 |
// import AppRouter from "./pages/AppRouter.js"; |
9 | 9 |
import createAppRouter from "./pages/AppRouter.js"; |
10 | 10 |
import App from "./pages/App.vue"; |
11 |
-import store from "./pages/AppStore.js"; |
|
11 |
+import createAppStore from "./pages/AppStore.js"; |
|
12 | 12 |
import COMMON_UTIL from "../resources/js/common.js"; |
13 | 13 |
import filters from './common/filters.js'; |
14 | 14 |
import cmmnPlugin from './common/commonPlugin.js'; |
... | ... | @@ -18,12 +18,26 @@ |
18 | 18 |
import VueDatePicker from '@vuepic/vue-datepicker'; |
19 | 19 |
import '@vuepic/vue-datepicker/dist/main.css' |
20 | 20 |
import '../resources/scss/main.scss'; |
21 |
+import { getCntxtPth } from "../resources/api/cntxtPth.js"; |
|
22 |
+import { getStorageMode, getLoginMode } from "../resources/api/loginPolicy.js"; |
|
21 | 23 |
|
22 | 24 |
async function initVueApp() { |
23 |
- const savedLoginMode = localStorage.getItem("loginMode"); |
|
24 |
- if (savedLoginMode) { |
|
25 |
- store.commit("setLoginMode", savedLoginMode); |
|
26 |
- } |
|
25 |
+ const ctx = await contextPath(); |
|
26 |
+ const strgMode = await storageMode(); |
|
27 |
+ const lgnMode = await loginMode(); |
|
28 |
+ console.log("Context Path:", ctx); |
|
29 |
+ console.log("Storage Mode:", strgMode); |
|
30 |
+ console.log("Login Mode:", lgnMode); |
|
31 |
+ |
|
32 |
+ const store = createAppStore(ctx, strgMode, lgnMode); |
|
33 |
+ |
|
34 |
+ // const savedLoginMode = localStorage.getItem("loginMode"); |
|
35 |
+ // const savedLoginMode = JSON.parse(localStorage.getItem("vuex"))?.loginMode; |
|
36 |
+ // console.log("Saved Login Mode:", savedLoginMode); |
|
37 |
+ // if (savedLoginMode) { |
|
38 |
+ // console.log("Store loginMode:", store.state.loginMode); |
|
39 |
+ // // store.commit("setLoginMode", savedLoginMode); |
|
40 |
+ // } |
|
27 | 41 |
|
28 | 42 |
const router = await createAppRouter() |
29 | 43 |
const vue = createApp(App) |
... | ... | @@ -43,4 +57,60 @@ |
43 | 57 |
|
44 | 58 |
vue.mount("#root"); |
45 | 59 |
} |
60 |
+ |
|
61 |
+// Context Path 조회 |
|
62 |
+async function contextPath() { |
|
63 |
+ try { |
|
64 |
+ const res = await getCntxtPth(); |
|
65 |
+ if (res.status == 200) { |
|
66 |
+ return res.data.data; |
|
67 |
+ } |
|
68 |
+ return null; |
|
69 |
+ } catch (error) { |
|
70 |
+ console.log("Error fetching context path:", error); |
|
71 |
+ const errorData = error.response.data; |
|
72 |
+ if (errorData.message != null && errorData.message != "") { |
|
73 |
+ alert(error.response.data.message); |
|
74 |
+ } else { |
|
75 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
76 |
+ } |
|
77 |
+ } |
|
78 |
+}; |
|
79 |
+ |
|
80 |
+// 스토리지 방식 조회 |
|
81 |
+async function storageMode() { |
|
82 |
+ try { |
|
83 |
+ const res = await getStorageMode (); |
|
84 |
+ if (res.status == 200) { |
|
85 |
+ return res.data.data; |
|
86 |
+ } |
|
87 |
+ return null; |
|
88 |
+ } catch (error) { |
|
89 |
+ const errorData = error.response.data; |
|
90 |
+ if (errorData.message != null && errorData.message != "") { |
|
91 |
+ alert(error.response.data.message); |
|
92 |
+ } else { |
|
93 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
94 |
+ } |
|
95 |
+ } |
|
96 |
+}; |
|
97 |
+ |
|
98 |
+// 로그인 방식 조회 |
|
99 |
+async function loginMode() { |
|
100 |
+ try { |
|
101 |
+ const res = await getLoginMode(); |
|
102 |
+ if (res.status == 200) { |
|
103 |
+ return res.data.data; |
|
104 |
+ } |
|
105 |
+ return null; |
|
106 |
+ } catch (error) { |
|
107 |
+ const errorData = error.response.data; |
|
108 |
+ if (errorData.message != null && errorData.message != "") { |
|
109 |
+ alert(error.response.data.message); |
|
110 |
+ } else { |
|
111 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
112 |
+ } |
|
113 |
+ } |
|
114 |
+}; |
|
115 |
+ |
|
46 | 116 |
initVueApp();(파일 끝에 줄바꿈 문자 없음) |
--- client/views/layout/AdminHeader copy.vue
+++ client/views/layout/AdminHeader copy.vue
... | ... | @@ -14,7 +14,6 @@ |
14 | 14 |
</template> |
15 | 15 |
|
16 | 16 |
<script> |
17 |
-import store from "../../views/pages/AppStore"; |
|
18 | 17 |
import queryParams from '../../resources/js/queryParams'; |
19 | 18 |
import { defaultSearchParams } from '../../resources/js/defaultSearchParams'; |
20 | 19 |
import { findBySysMenu } from '../../resources/api/menu'; |
... | ... | @@ -37,7 +36,7 @@ |
37 | 36 |
}, |
38 | 37 |
methods: { |
39 | 38 |
menuCheck() { |
40 |
- const menu = store.state.menu; |
|
39 |
+ const menu = this.$store.state.menu; |
|
41 | 40 |
if(menu != null && menu != '' && menu != undefined) { |
42 | 41 |
this.checkMenu = menu.menuId; |
43 | 42 |
} |
... | ... | @@ -46,8 +45,8 @@ |
46 | 45 |
async findAll() { |
47 | 46 |
try { |
48 | 47 |
const params = { |
49 |
- roles : store.state.roles.map(auth => auth.authority), |
|
50 |
- menuType : store.state.userType |
|
48 |
+ roles : this.$store.state.roles.map(auth => auth.authority), |
|
49 |
+ menuType : this.$store.state.userType |
|
51 | 50 |
}; |
52 | 51 |
const res = await findBySysMenu(params); |
53 | 52 |
if(res.status == 200) { |
--- client/views/layout/AdminHeader.vue
+++ client/views/layout/AdminHeader.vue
... | ... | @@ -20,7 +20,6 @@ |
20 | 20 |
</template> |
21 | 21 |
|
22 | 22 |
<script> |
23 |
-import store from "../../views/pages/AppStore"; |
|
24 | 23 |
import queryParams from '../../resources/js/queryParams'; |
25 | 24 |
import { mapActions } from "vuex"; |
26 | 25 |
import { cacheReSet } from "../../resources/api/cacheReSet"; |
... | ... | @@ -33,7 +32,7 @@ |
33 | 32 |
}, |
34 | 33 |
data() { |
35 | 34 |
return { |
36 |
- mbrNm: store.state.mbrNm, |
|
35 |
+ mbrNm: this.$store.state.mbrNm, |
|
37 | 36 |
} |
38 | 37 |
}, |
39 | 38 |
created() { |
... | ... | @@ -76,7 +75,7 @@ |
76 | 75 |
computed: { |
77 | 76 |
pgNm() { |
78 | 77 |
const route = this.$route; |
79 |
- const storeMenu = store.state.menu; |
|
78 |
+ const storeMenu = this.$store.state.menu; |
|
80 | 79 |
|
81 | 80 |
if (route?.meta?.korName) { |
82 | 81 |
if (route.path === '/adm/main.page') { |
--- client/views/layout/AdminMenu copy.vue
+++ client/views/layout/AdminMenu copy.vue
... | ... | @@ -41,7 +41,6 @@ |
41 | 41 |
</nav> |
42 | 42 |
</template> |
43 | 43 |
<script> |
44 |
-import store from "../pages/AppStore"; |
|
45 | 44 |
import queryParams from "../../resources/js/queryParams"; |
46 | 45 |
import { defaultSearchParams } from "../../resources/js/defaultSearchParams"; |
47 | 46 |
import { mapActions } from "vuex"; |
... | ... | @@ -54,7 +53,7 @@ |
54 | 53 |
props: {}, |
55 | 54 |
data() { |
56 | 55 |
return { |
57 |
- mbrNm: store.state.mbrNm, |
|
56 |
+ mbrNm: this.$store.state.mbrNm, |
|
58 | 57 |
currentPath: this.$route.path, |
59 | 58 |
resetSearch: { ...defaultSearchParams }, |
60 | 59 |
menuList: [], |
... | ... | @@ -65,7 +64,7 @@ |
65 | 64 |
}, |
66 | 65 |
methods: { |
67 | 66 |
menuCheck() { |
68 |
- const menu = store.state.menu; |
|
67 |
+ const menu = this.$store.state.menu; |
|
69 | 68 |
if (menu != null && menu != "" && menu != undefined) { |
70 | 69 |
this.menuList = menu.childList; |
71 | 70 |
} |
--- client/views/layout/AdminMenu.vue
+++ client/views/layout/AdminMenu.vue
... | ... | @@ -54,7 +54,6 @@ |
54 | 54 |
</template> |
55 | 55 |
|
56 | 56 |
<script> |
57 |
-import store from "../pages/AppStore"; |
|
58 | 57 |
import queryParams from '../../resources/js/queryParams'; |
59 | 58 |
import { defaultSearchParams } from '../../resources/js/defaultSearchParams'; |
60 | 59 |
import cntnStatsSave from "../../resources/js/cntnStatsSave"; |
... | ... | @@ -82,7 +81,7 @@ |
82 | 81 |
methods: { |
83 | 82 |
// 새로고침 시 메뉴 체크 |
84 | 83 |
menuCheck() { |
85 |
- let menu = store.state.menu; |
|
84 |
+ let menu = this.$store.state.menu; |
|
86 | 85 |
if (menu) { |
87 | 86 |
// this.checkMenu = menu.menuId; |
88 | 87 |
this.activeMenus = this.getParentMenus(menu); |
... | ... | @@ -96,8 +95,8 @@ |
96 | 95 |
async findAll() { |
97 | 96 |
try { |
98 | 97 |
const params = { |
99 |
- roles: store.state.roles.map(auth => auth.authority), |
|
100 |
- menuType: store.state.userType |
|
98 |
+ roles: this.$store.state.roles.map(auth => auth.authority), |
|
99 |
+ menuType: this.$store.state.userType |
|
101 | 100 |
}; |
102 | 101 |
const res = await findBySysMenu(params); |
103 | 102 |
if (res.status === 200) { |
--- client/views/layout/UserMenu.vue
+++ client/views/layout/UserMenu.vue
... | ... | @@ -110,7 +110,6 @@ |
110 | 110 |
</template> |
111 | 111 |
|
112 | 112 |
<script> |
113 |
-import store from "../../views/pages/AppStore"; |
|
114 | 113 |
import { findBySysMenu } from "../../resources/api/menu"; |
115 | 114 |
import queryParams from "../../resources/js/queryParams"; |
116 | 115 |
import { defaultSearchParams } from "../../resources/js/defaultSearchParams"; |
... | ... | @@ -123,7 +122,7 @@ |
123 | 122 |
return { |
124 | 123 |
pageRole: this.$store.state.userType, |
125 | 124 |
currentOpenIndex: null, |
126 |
- roles: store.state.roles || [], |
|
125 |
+ roles: this.$store.state.roles || [], |
|
127 | 126 |
menuList: [], |
128 | 127 |
currentActiveIndex: null, |
129 | 128 |
currentSubActiveIndex: null, |
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
... | ... | @@ -1,5 +1,5 @@ |
1 | 1 |
import { createWebHistory, createRouter } from "vue-router"; |
2 |
-import store from "./AppStore"; |
|
2 |
+import { getGlobalStore } from "./AppStore"; |
|
3 | 3 |
import filters from '../common/filters'; |
4 | 4 |
|
5 | 5 |
// 메인화면 |
... | ... | @@ -32,6 +32,7 @@ |
32 | 32 |
// Context Path 정보 호출 |
33 | 33 |
async function getContextPath() { |
34 | 34 |
try { |
35 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
35 | 36 |
const res = await getCntxtPth(); |
36 | 37 |
if (res.status == 200) { |
37 | 38 |
let ctx = res.data.data || ''; // Context Path 정보 |
... | ... | @@ -52,6 +53,7 @@ |
52 | 53 |
// 라우터 정보 호출 |
53 | 54 |
async function fetchRoutes() { |
54 | 55 |
try { |
56 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
55 | 57 |
const res = await findAll(); |
56 | 58 |
if (res.status == 200) { |
57 | 59 |
const newRoutes = res.data.data.map(route => ({ |
... | ... | @@ -139,6 +141,7 @@ |
139 | 141 |
|
140 | 142 |
// 권한 검증 |
141 | 143 |
function isValidRole() { |
144 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
142 | 145 |
const roles = store.state.roles; |
143 | 146 |
if (!Array.isArray(roles)) { |
144 | 147 |
store.commit("setStoreReset"); |
... | ... | @@ -167,6 +170,7 @@ |
167 | 170 |
}); |
168 | 171 |
|
169 | 172 |
AppRouter.beforeEach(async (to, from, next) => { |
173 |
+ const store = getGlobalStore(); // 전역 스토어 가져오기 |
|
170 | 174 |
const contextPath = store.state.contextPath; // Context Path 정보 |
171 | 175 |
const admPath = to.path.includes('/adm'); // 관리자 페이지 여부 (true: 관리자 페이지, false: 사용자 페이지) |
172 | 176 |
|
--- client/views/pages/AppStore.js
+++ client/views/pages/AppStore.js
... | ... | @@ -2,185 +2,205 @@ |
2 | 2 |
import createPersistedState from "vuex-persistedstate"; |
3 | 3 |
import { logOutProc } from "../../resources/api/logOut" |
4 | 4 |
|
5 |
-export default createStore({ |
|
6 |
- plugins: [createPersistedState({ |
|
7 |
- paths: ['loginMode', 'authorization', 'mbrId', 'mbrNm', 'roles', 'contextPath', 'pageAuth'] |
|
8 |
- })], |
|
9 |
- state: { |
|
10 |
- authorization: null, |
|
11 |
- // refresh: null, |
|
12 |
- loginMode: 'J', |
|
13 |
- userType: "portal", |
|
14 |
- menu: null, |
|
15 |
- path: null, |
|
16 |
- roles: [{authority: "ROLE_NONE"}], |
|
17 |
- pageAuth: null, |
|
18 |
- contextPath: null, |
|
19 |
- }, |
|
20 |
- getters: { |
|
21 |
- getAuthorization: function () {}, |
|
22 |
- // getRefresh: function () {}, |
|
23 |
- getMbrNm: function () {}, |
|
24 |
- getRoles: function () {}, |
|
25 |
- getLoginMode: state => state.loginMode, |
|
26 |
- }, |
|
27 |
- mutations: { |
|
28 |
- setAuthorization(state, newValue) { |
|
29 |
- state.authorization = newValue; |
|
30 |
- }, |
|
31 |
- // setRefresh(state, newValue) { |
|
32 |
- // state.refresh = newValue; |
|
33 |
- // }, |
|
34 |
- setMbrNm(state, newValue) { |
|
35 |
- state.mbrNm = newValue; |
|
36 |
- }, |
|
37 |
- setMbrId(state, newValue) { |
|
38 |
- state.mbrId = newValue; |
|
39 |
- }, |
|
40 |
- setRoles(state, newValue) { |
|
41 |
- state.roles = newValue; |
|
42 |
- }, |
|
43 |
- setUserType(state, newValue) { |
|
44 |
- state.userType = newValue; |
|
45 |
- }, |
|
46 |
- setMenu(state, newValue) { |
|
47 |
- state.menu = newValue; |
|
48 |
- }, |
|
49 |
- setPath(state, newValue) { |
|
50 |
- state.path = newValue; |
|
51 |
- }, |
|
52 |
- setStoreReset(state) { |
|
53 |
- state.authorization = null; |
|
54 |
- // state.refresh = null; |
|
55 |
- state.loginMode = 'J'; |
|
56 |
- state.mbrNm = null; |
|
57 |
- state.mbrId = null; |
|
58 |
- state.roles = [{authority: "ROLE_NONE"}]; |
|
59 |
- state.menu = null; |
|
60 |
- state.pageAuth = null; |
|
61 |
- state.contextPath = null; |
|
62 |
- }, |
|
63 |
- setPageAuth(state, newValue) { |
|
64 |
- state.pageAuth = newValue; |
|
65 |
- }, |
|
66 |
- setMenuList(state, menuList) { |
|
67 |
- state.menuList = menuList; |
|
68 |
- // 메뉴트리 펼치기 |
|
69 |
- const flattenMenus = (menus) => { |
|
70 |
- const result = []; |
|
5 |
+let globalStore = null; |
|
71 | 6 |
|
72 |
- for (const menu of menus) { |
|
73 |
- result.push(menu); |
|
74 |
- if (menu.childList?.length) { |
|
75 |
- result.push(...flattenMenus(menu.childList)); |
|
76 |
- } |
|
77 |
- } |
|
7 |
+// 전역 스토어 설정 함수 |
|
8 |
+export function setGlobalStore(store) { |
|
9 |
+ globalStore = store; |
|
10 |
+} |
|
78 | 11 |
|
79 |
- return result; |
|
80 |
- } |
|
81 |
- const flattenedMenuList = flattenMenus(menuList); |
|
82 |
- state.flatMenuList = flattenedMenuList; |
|
12 |
+// 전역 스토어 호출 함수 |
|
13 |
+export function getGlobalStore() { |
|
14 |
+ return globalStore; |
|
15 |
+} |
|
16 |
+ |
|
17 |
+export default function createAppStore(ctx, strgMode, lgnMode) { |
|
18 |
+ const store = createStore({ |
|
19 |
+ plugins: [createPersistedState({ |
|
20 |
+ // storage: window.sessionStorage, |
|
21 |
+ storage: strgMode === 'S' ? window.sessionStorage : window.localStorage, |
|
22 |
+ paths: ['loginMode', 'authorization', 'mbrId', 'mbrNm', 'roles', 'contextPath', 'pageAuth'] |
|
23 |
+ })], |
|
24 |
+ state: { |
|
25 |
+ authorization: null, |
|
26 |
+ // refresh: null, |
|
27 |
+ loginMode: lgnMode || 'J', |
|
28 |
+ userType: "portal", |
|
29 |
+ menu: null, |
|
30 |
+ path: null, |
|
31 |
+ roles: [{authority: "ROLE_NONE"}], |
|
32 |
+ pageAuth: null, |
|
33 |
+ contextPath: ctx || null, |
|
83 | 34 |
}, |
84 |
- setContextPath(state, ctx) { |
|
85 |
- state.contextPath = ctx; |
|
35 |
+ getters: { |
|
36 |
+ getAuthorization: function () {}, |
|
37 |
+ // getRefresh: function () {}, |
|
38 |
+ getMbrNm: function () {}, |
|
39 |
+ getRoles: function () {}, |
|
40 |
+ getLoginMode: state => state.loginMode, |
|
86 | 41 |
}, |
87 |
- setLoginMode(state, value) { |
|
88 |
- state.loginMode = value; |
|
89 |
- }, |
|
90 |
- }, |
|
91 |
- actions: { |
|
92 |
- async logout({ commit }) { |
|
93 |
- try { |
|
94 |
- const ctx = this.state.contextPath; // 캐시 초기화 전 contextPath 저장 |
|
95 |
- const admPath = this.state.path?.includes("/adm") // 캐시 초기화 전 경로 구분 (true: 관리자 페이지, false: 사용자 페이지) |
|
96 |
- const loginMode = this.state.loginMode || localStorage.getItem('loginMode') || 'J'; |
|
97 |
- |
|
98 |
- // 로그인 모드에 따른 처리 |
|
99 |
- if (loginMode === 'J') { |
|
100 |
- // JWT 방식인 경우만 서버 API 호출 |
|
101 |
- try { |
|
102 |
- const res = await logOutProc(); |
|
103 |
- if (res.data.message) { |
|
104 |
- alert(res.data.message); |
|
42 |
+ mutations: { |
|
43 |
+ setAuthorization(state, newValue) { |
|
44 |
+ state.authorization = newValue; |
|
45 |
+ }, |
|
46 |
+ // setRefresh(state, newValue) { |
|
47 |
+ // state.refresh = newValue; |
|
48 |
+ // }, |
|
49 |
+ setMbrNm(state, newValue) { |
|
50 |
+ state.mbrNm = newValue; |
|
51 |
+ }, |
|
52 |
+ setMbrId(state, newValue) { |
|
53 |
+ state.mbrId = newValue; |
|
54 |
+ }, |
|
55 |
+ setRoles(state, newValue) { |
|
56 |
+ state.roles = newValue; |
|
57 |
+ }, |
|
58 |
+ setUserType(state, newValue) { |
|
59 |
+ state.userType = newValue; |
|
60 |
+ }, |
|
61 |
+ setMenu(state, newValue) { |
|
62 |
+ state.menu = newValue; |
|
63 |
+ }, |
|
64 |
+ setPath(state, newValue) { |
|
65 |
+ state.path = newValue; |
|
66 |
+ }, |
|
67 |
+ setStoreReset(state) { |
|
68 |
+ state.authorization = null; |
|
69 |
+ // state.refresh = null; |
|
70 |
+ state.loginMode = 'J'; |
|
71 |
+ state.mbrNm = null; |
|
72 |
+ state.mbrId = null; |
|
73 |
+ state.roles = [{authority: "ROLE_NONE"}]; |
|
74 |
+ state.menu = null; |
|
75 |
+ state.pageAuth = null; |
|
76 |
+ state.contextPath = null; |
|
77 |
+ }, |
|
78 |
+ setPageAuth(state, newValue) { |
|
79 |
+ state.pageAuth = newValue; |
|
80 |
+ }, |
|
81 |
+ setMenuList(state, menuList) { |
|
82 |
+ state.menuList = menuList; |
|
83 |
+ // 메뉴트리 펼치기 |
|
84 |
+ const flattenMenus = (menus) => { |
|
85 |
+ const result = []; |
|
86 |
+ |
|
87 |
+ for (const menu of menus) { |
|
88 |
+ result.push(menu); |
|
89 |
+ if (menu.childList?.length) { |
|
90 |
+ result.push(...flattenMenus(menu.childList)); |
|
105 | 91 |
} |
106 |
- } catch (error) { |
|
107 |
- console.log(error); |
|
108 |
- // API 에러가 발생해도 클라이언트는 정리 |
|
109 | 92 |
} |
110 |
- } |
|
111 |
- |
|
112 |
- // 1. 상태 초기화 |
|
113 |
- commit("setStoreReset"); |
|
114 |
- |
|
115 |
- // 2. 로컬스토리지와 세션스토리지 초기화 |
|
116 |
- localStorage.clear(); |
|
117 |
- sessionStorage.clear(); |
|
118 | 93 |
|
119 |
- // 3. 모든 가능한 쿠키 삭제 (OAuth 관련 포함) |
|
120 |
- const cookiesToDelete = [ |
|
121 |
- 'refresh', |
|
122 |
- 'Authorization', |
|
123 |
- 'JSESSIONID', |
|
124 |
- 'oauth_access_token', // OAuth 토큰 쿠키 |
|
125 |
- 'oauth_refresh_token', // OAuth 리프레시 토큰 |
|
126 |
- 'SESSION' // 스프링 기본 세션 쿠키 |
|
127 |
- ]; |
|
128 |
- |
|
129 |
- cookiesToDelete.forEach(cookieName => { |
|
130 |
- document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; |
|
131 |
- document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname};`; |
|
132 |
- }); |
|
133 |
- |
|
134 |
- // 4. 로그인 페이지로 이동 (OAuth 관련 파라미터 제거) |
|
135 |
- const cleanUrl = admPath ? |
|
136 |
- ctx + "/cmslogin.page" : |
|
137 |
- ctx + "/login.page"; |
|
138 |
- |
|
139 |
- // URL에서 OAuth 관련 파라미터 제거 |
|
140 |
- window.history.replaceState({}, document.title, cleanUrl); |
|
141 |
- window.location.href = cleanUrl; |
|
142 |
- |
|
143 |
- } catch(error) { |
|
144 |
- console.error("로그아웃 처리 중 오류:", error); |
|
145 |
- |
|
146 |
- // 에러가 발생해도 클라이언트 상태는 정리 |
|
147 |
- commit("setStoreReset"); |
|
148 |
- localStorage.clear(); |
|
149 |
- sessionStorage.clear(); |
|
150 |
- |
|
151 |
- const ctx = this.state.contextPath; |
|
152 |
- const admPath = this.state.path?.includes("/adm"); |
|
153 |
- |
|
154 |
- // 에러 메시지 표시 |
|
155 |
- const errorData = error.response?.data; |
|
156 |
- if (errorData?.message) { |
|
157 |
- alert(errorData.message); |
|
158 |
- } else { |
|
159 |
- console.log("로그아웃 처리 중 예상치 못한 오류 발생"); |
|
94 |
+ return result; |
|
160 | 95 |
} |
161 |
- |
|
162 |
- // 로그인 페이지로 이동 |
|
163 |
- const cleanUrl = admPath ? |
|
164 |
- ctx + "/cmslogin.page" : |
|
165 |
- ctx + "/login.page"; |
|
96 |
+ const flattenedMenuList = flattenMenus(menuList); |
|
97 |
+ state.flatMenuList = flattenedMenuList; |
|
98 |
+ }, |
|
99 |
+ setContextPath(state, ctx) { |
|
100 |
+ state.contextPath = ctx; |
|
101 |
+ }, |
|
102 |
+ setLoginMode(state, value) { |
|
103 |
+ state.loginMode = value; |
|
104 |
+ }, |
|
105 |
+ }, |
|
106 |
+ actions: { |
|
107 |
+ async logout({ commit }) { |
|
108 |
+ try { |
|
109 |
+ const ctx = this.state.contextPath; // 캐시 초기화 전 contextPath 저장 |
|
110 |
+ const admPath = this.state.path?.includes("/adm") // 캐시 초기화 전 경로 구분 (true: 관리자 페이지, false: 사용자 페이지) |
|
111 |
+ const loginMode = this.state.loginMode || localStorage.getItem('loginMode') || 'J'; |
|
166 | 112 |
|
167 |
- window.location.href = cleanUrl; |
|
168 |
- } |
|
113 |
+ // 로그인 모드에 따른 처리 |
|
114 |
+ if (loginMode === 'J') { |
|
115 |
+ // JWT 방식인 경우만 서버 API 호출 |
|
116 |
+ try { |
|
117 |
+ const res = await logOutProc(); |
|
118 |
+ if (res.data.message) { |
|
119 |
+ alert(res.data.message); |
|
120 |
+ } |
|
121 |
+ } catch (error) { |
|
122 |
+ console.log(error); |
|
123 |
+ // API 에러가 발생해도 클라이언트는 정리 |
|
124 |
+ } |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ // 1. 상태 초기화 |
|
128 |
+ commit("setStoreReset"); |
|
129 |
+ |
|
130 |
+ // 2. 로컬스토리지와 세션스토리지 초기화 |
|
131 |
+ localStorage.clear(); |
|
132 |
+ sessionStorage.clear(); |
|
133 |
+ |
|
134 |
+ // 3. 모든 가능한 쿠키 삭제 (OAuth 관련 포함) |
|
135 |
+ const cookiesToDelete = [ |
|
136 |
+ 'refresh', |
|
137 |
+ 'Authorization', |
|
138 |
+ 'JSESSIONID', |
|
139 |
+ 'oauth_access_token', // OAuth 토큰 쿠키 |
|
140 |
+ 'oauth_refresh_token', // OAuth 리프레시 토큰 |
|
141 |
+ 'SESSION' // 스프링 기본 세션 쿠키 |
|
142 |
+ ]; |
|
143 |
+ |
|
144 |
+ cookiesToDelete.forEach(cookieName => { |
|
145 |
+ document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`; |
|
146 |
+ document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${window.location.hostname};`; |
|
147 |
+ }); |
|
148 |
+ |
|
149 |
+ // 4. 로그인 페이지로 이동 (OAuth 관련 파라미터 제거) |
|
150 |
+ const cleanUrl = admPath ? |
|
151 |
+ ctx + "/cmslogin.page" : |
|
152 |
+ ctx + "/login.page"; |
|
153 |
+ |
|
154 |
+ // URL에서 OAuth 관련 파라미터 제거 |
|
155 |
+ window.history.replaceState({}, document.title, cleanUrl); |
|
156 |
+ window.location.href = cleanUrl; |
|
157 |
+ |
|
158 |
+ } catch(error) { |
|
159 |
+ console.error("로그아웃 처리 중 오류:", error); |
|
160 |
+ |
|
161 |
+ // 에러가 발생해도 클라이언트 상태는 정리 |
|
162 |
+ commit("setStoreReset"); |
|
163 |
+ localStorage.clear(); |
|
164 |
+ sessionStorage.clear(); |
|
165 |
+ |
|
166 |
+ const ctx = this.state.contextPath; |
|
167 |
+ const admPath = this.state.path?.includes("/adm"); |
|
168 |
+ |
|
169 |
+ // 에러 메시지 표시 |
|
170 |
+ const errorData = error.response?.data; |
|
171 |
+ if (errorData?.message) { |
|
172 |
+ alert(errorData.message); |
|
173 |
+ } else { |
|
174 |
+ console.log("로그아웃 처리 중 예상치 못한 오류 발생"); |
|
175 |
+ } |
|
176 |
+ |
|
177 |
+ // 로그인 페이지로 이동 |
|
178 |
+ const cleanUrl = admPath ? |
|
179 |
+ ctx + "/cmslogin.page" : |
|
180 |
+ ctx + "/login.page"; |
|
181 |
+ |
|
182 |
+ window.location.href = cleanUrl; |
|
183 |
+ } |
|
184 |
+ }, |
|
185 |
+ setUserType({ commit }, userType) { |
|
186 |
+ commit("setUserType", userType); |
|
187 |
+ }, |
|
188 |
+ setMenu({ commit }, menu) { |
|
189 |
+ commit("setMenu", menu); |
|
190 |
+ }, |
|
191 |
+ setPath({ commit }, path) { |
|
192 |
+ commit("setPath", path); |
|
193 |
+ }, |
|
194 |
+ setPageAuth({ commit }, pageAuth) { |
|
195 |
+ commit("setPageAuth", pageAuth); |
|
196 |
+ }, |
|
197 |
+ setStoreReset({commit}) { |
|
198 |
+ commit("setStoreReset"); |
|
199 |
+ }, |
|
169 | 200 |
}, |
170 |
- setUserType({ commit }, userType) { |
|
171 |
- commit("setUserType", userType); |
|
172 |
- }, |
|
173 |
- setMenu({ commit }, menu) { |
|
174 |
- commit("setMenu", menu); |
|
175 |
- }, |
|
176 |
- setPath({ commit }, path) { |
|
177 |
- commit("setPath", path); |
|
178 |
- }, |
|
179 |
- setPageAuth({ commit }, pageAuth) { |
|
180 |
- commit("setPageAuth", pageAuth); |
|
181 |
- }, |
|
182 |
- setStoreReset({commit}) { |
|
183 |
- commit("setStoreReset"); |
|
184 |
- }, |
|
185 |
- }, |
|
186 |
-});(파일 끝에 줄바꿈 문자 없음) |
|
201 |
+ }); |
|
202 |
+ |
|
203 |
+ setGlobalStore(store); // 전역 스토어 설정 |
|
204 |
+ |
|
205 |
+ return store; |
|
206 |
+}(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
... | ... | @@ -47,6 +47,26 @@ |
47 | 47 |
</div> |
48 | 48 |
</div> |
49 | 49 |
<div class="layout"> |
50 |
+ <label class="form-title">스토리지 방식 설정</label> |
|
51 |
+ <div class="form-group"> |
|
52 |
+ <div class="check-area"> |
|
53 |
+ <div class="form-check"> |
|
54 |
+ <input type="radio" id="storageModeL" class="mr5" value="L" v-model="strgMode" |
|
55 |
+ @change="saveByStorageMode" /> |
|
56 |
+ <label for="storageModeL">LOCAL 방식</label> |
|
57 |
+ </div> |
|
58 |
+ <div class="form-check"> |
|
59 |
+ <input type="radio" id="storageModeS" class="mr5" value="S" v-model="strgMode" |
|
60 |
+ @change="saveByStorageMode" /> |
|
61 |
+ <label for="storageModeS">SESSION 방식</label> |
|
62 |
+ </div> |
|
63 |
+ </div> |
|
64 |
+ <!-- <span class="ml10 gray"> |
|
65 |
+ 현재 로그인 방식은 <strong>{{ loginModeLabel }}</strong> 입니다. |
|
66 |
+ </span> --> |
|
67 |
+ </div> |
|
68 |
+ </div> |
|
69 |
+ <div class="layout"> |
|
50 | 70 |
<label class="form-title">이메일 2차 인증 설정</label> |
51 | 71 |
<div class="form-group"> |
52 | 72 |
<div class="check-area"> |
... | ... | @@ -63,8 +83,6 @@ |
63 | 83 |
</div> |
64 | 84 |
<!-- <p>{{ allowMultipleLogin ? '중복 로그인을 허용하고 있습니다.' : '중복 로그인을 허용하지 않습니다.' }}</p>--> |
65 | 85 |
</div> |
66 |
- </div> |
|
67 |
- <div class="layout"> |
|
68 | 86 |
</div> |
69 | 87 |
<div class="layout"> |
70 | 88 |
<label class="form-title">Context Path 설정</label> |
... | ... | @@ -88,10 +106,9 @@ |
88 | 106 |
</template> |
89 | 107 |
|
90 | 108 |
<script> |
91 |
-import { findAllByLoginPolicy, saveByLoginPolicy, findAllByLoginMode, saveByLoginMode, findAllBy2ndAuth, saveBy2ndAuth } from '../../../../../resources/api/loginPolicy.js'; |
|
109 |
+import { findAllByLoginPolicy, saveByLoginPolicy, findAllByLoginMode, saveByLoginMode, findAllBy2ndAuth, saveBy2ndAuth, findAllByStorageMode, saveByStorageMode } from '../../../../../resources/api/loginPolicy.js'; |
|
92 | 110 |
import { getCntxtPth, saveCntxtPth } from '../../../../../resources/api/cntxtPth'; |
93 | 111 |
import { cacheReSet } from "../../../../../resources/api/cacheReSet"; |
94 |
-import store from "../../../../../views/pages/AppStore"; |
|
95 | 112 |
export default { |
96 | 113 |
data() { |
97 | 114 |
return { |
... | ... | @@ -105,6 +122,9 @@ |
105 | 122 |
|
106 | 123 |
use2ndAuth: null, // 2차 인증 사용 여부 |
107 | 124 |
previousUse2ndAuth: null, // 이전 2차 인증 사용 여부 저장 |
125 |
+ |
|
126 |
+ strgMode: null, // 스토리지 방식 |
|
127 |
+ previousStrgMode: null, // 이전 스토리지 방식 저장 |
|
108 | 128 |
} |
109 | 129 |
}, |
110 | 130 |
created() { |
... | ... | @@ -130,6 +150,9 @@ |
130 | 150 |
const res3 = await findAllBy2ndAuth(); |
131 | 151 |
this.use2ndAuth = res3.data.data === true ? 'Y' : 'N'; |
132 | 152 |
this.previousUse2ndAuth = this.use2ndAuth; // 초기 상태를 저장 |
153 |
+ const res4 = await findAllByStorageMode(); |
|
154 |
+ this.strgMode = res4.data.data; |
|
155 |
+ this.previousStrgMode = this.strgMode; // 초기 상태를 저장 |
|
133 | 156 |
} catch (err) { |
134 | 157 |
alert('설정 정보를 불러오는 데 실패했습니다.'); |
135 | 158 |
} |
... | ... | @@ -148,7 +171,7 @@ |
148 | 171 |
loginPolicy.allowMultipleLogin = this.allowMultipleLogin; |
149 | 172 |
await saveByLoginPolicy(loginPolicy); |
150 | 173 |
alert('중복 로그인 설정이 저장되었습니다.'); |
151 |
- store.commit("setStoreReset"); |
|
174 |
+ this.$store.commit("setStoreReset"); |
|
152 | 175 |
window.location = this.$filters.ctxPath('/cmslogin.page'); |
153 | 176 |
} catch (err) { |
154 | 177 |
alert('중복 로그인 설정 저장 실패'+ (err.response?.data?.message || err.message)); |
... | ... | @@ -169,7 +192,7 @@ |
169 | 192 |
loginMode.lgnMode = this.lgnMode; |
170 | 193 |
await saveByLoginMode(loginMode); |
171 | 194 |
alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
172 |
- store.commit("setStoreReset"); |
|
195 |
+ this.$store.commit("setStoreReset"); |
|
173 | 196 |
window.location = this.$filters.ctxPath('/cmslogin.page'); |
174 | 197 |
} catch (err) { |
175 | 198 |
alert('로그인 방식 저장 실패: ' + (err.response?.data?.message || err.message)); |
... | ... | @@ -212,14 +235,14 @@ |
212 | 235 |
if (storeCtx == '/') { |
213 | 236 |
storeCtx = ''; |
214 | 237 |
} |
215 |
- store.commit("setContextPath", storeCtx); // 캐시 초기화 요청을 보내기 위한 Context Path 정보 저장 |
|
238 |
+ this.$store.commit("setContextPath", storeCtx); // 캐시 초기화 요청을 보내기 위한 Context Path 정보 저장 |
|
216 | 239 |
await this.$store.dispatch("logout"); |
217 | 240 |
/* const cacheRes = await cacheReSet(); // 캐시 초기화 |
218 | 241 |
if (cacheRes.status !== 200) { |
219 | 242 |
alert(cacheRes.data.message); |
220 | 243 |
} |
221 |
- store.commit("setStoreReset"); // 캐시 초기화 후 Store 초기화 |
|
222 |
- store.commit("setContextPath", storeCtx); // 라우터 Context Path 정보 저장 |
|
244 |
+ this.$store.commit("setStoreReset"); // 캐시 초기화 후 Store 초기화 |
|
245 |
+ this.$store.commit("setContextPath", storeCtx); // 라우터 Context Path 정보 저장 |
|
223 | 246 |
window.location.href = `${storeCtx}/login.page`; |
224 | 247 |
// window.location.href = `${storeCtx}/adm/main.page`; */ |
225 | 248 |
} else { |
... | ... | @@ -277,15 +300,43 @@ |
277 | 300 |
email2ndAuth.useYn = this.use2ndAuth; |
278 | 301 |
await saveBy2ndAuth(email2ndAuth); |
279 | 302 |
alert('이메일 2차 인증 설정이 저장되었습니다.'); |
280 |
- store.commit("setStoreReset"); |
|
303 |
+ // this.$store.commit("setStoreReset"); |
|
304 |
+ // window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
305 |
+ } catch (error) { |
|
306 |
+ const errorData = error.response.data; |
|
307 |
+ if (errorData.message != null && errorData.message != "") { |
|
308 |
+ alert(error.response.data.message); |
|
309 |
+ } else { |
|
310 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
311 |
+ } |
|
312 |
+ } |
|
313 |
+ }, |
|
314 |
+ |
|
315 |
+ // 스토리지 방식 저장 |
|
316 |
+ async saveByStorageMode() { |
|
317 |
+ const confirmed = confirm( |
|
318 |
+ '스토리지 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
|
319 |
+ ); |
|
320 |
+ if (!confirmed) { |
|
321 |
+ this.strgMode = this.previousStrgMode; |
|
322 |
+ return; |
|
323 |
+ } |
|
324 |
+ |
|
325 |
+ try { |
|
326 |
+ const storageMode = {}; |
|
327 |
+ storageMode.strgMode = this.strgMode; |
|
328 |
+ await saveByStorageMode(storageMode); |
|
329 |
+ alert('스토리지 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
|
330 |
+ this.$store.commit("setStoreReset"); |
|
281 | 331 |
window.location = this.$filters.ctxPath('/cmslogin.page'); |
282 | 332 |
} catch (error) { |
283 | 333 |
const errorData = error.response.data; |
284 |
- if (errorData.message != null && errorData.message != "") { |
|
285 |
- alert(error.response.data.message); |
|
286 |
- } else { |
|
287 |
- alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
288 |
- } |
|
334 |
+ if (errorData.message != null && errorData.message != "") { |
|
335 |
+ alert(error.response.data.message); |
|
336 |
+ } else { |
|
337 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
338 |
+ } |
|
339 |
+ this.strgMode = this.previousStrgMode; |
|
289 | 340 |
} |
290 | 341 |
}, |
291 | 342 |
} |
--- client/views/pages/login/AdminLogin.vue
+++ client/views/pages/login/AdminLogin.vue
... | ... | @@ -61,7 +61,7 @@ |
61 | 61 |
|
62 | 62 |
<script> |
63 | 63 |
import { useStore } from "vuex"; |
64 |
-import store from "../AppStore"; |
|
64 |
+// import store from "../AppStore"; |
|
65 | 65 |
import { loginProc } from "../../../resources/api/login"; |
66 | 66 |
import { check2ndAuthProc, sendAuthEmailProc } from "../../../resources/api/email"; |
67 | 67 |
import queryParams from "../../../resources/js/queryParams"; |
... | ... | @@ -76,7 +76,7 @@ |
76 | 76 |
pswd: null, |
77 | 77 |
lgnReqPage: 'A' |
78 | 78 |
}, |
79 |
- store: useStore(), |
|
79 |
+ // store: useStore(), |
|
80 | 80 |
isAdminPage: false, |
81 | 81 |
|
82 | 82 |
memberInfo: { |
... | ... | @@ -87,6 +87,8 @@ |
87 | 87 |
// 인증 절차 |
88 | 88 |
loginStep1: false, // 1차 인증 |
89 | 89 |
loginStep2: false, // 2차 인증 |
90 |
+ |
|
91 |
+ storageType: null, // 로컬 스토리지 타입 (세션/로컬) |
|
90 | 92 |
}; |
91 | 93 |
}, |
92 | 94 |
methods: { |
... | ... | @@ -184,6 +186,7 @@ |
184 | 186 |
// 로그인 성공 시 |
185 | 187 |
async loginSuccessProc(res) { |
186 | 188 |
const loginType = res.headers['login-type']; // 세션/토큰 로그인 구분 |
189 |
+ this.storageType = res.headers['storage-type']; // 로컬 스토리지 타입 (세션/로컬) |
|
187 | 190 |
if (loginType === 'J') { |
188 | 191 |
this.handleJWTLogin(res); |
189 | 192 |
// JWT 방식 |
... | ... | @@ -283,35 +286,35 @@ |
283 | 286 |
// 인증 정보 저장 |
284 | 287 |
setAuthInfo(loginMode, token, userInfo) { |
285 | 288 |
// Vuex 상태 저장 |
286 |
- store.commit("setLoginMode", loginMode); |
|
287 |
- store.commit("setAuthorization", token); |
|
288 |
- store.commit("setMbrId", userInfo.mbrId); |
|
289 |
- store.commit("setMbrNm", userInfo.mbrNm); |
|
290 |
- store.commit("setRoles", userInfo.roles); |
|
289 |
+ this.$store.commit("setLoginMode", loginMode); |
|
290 |
+ this.$store.commit("setAuthorization", token); |
|
291 |
+ this.$store.commit("setMbrId", userInfo.mbrId); |
|
292 |
+ this.$store.commit("setMbrNm", userInfo.mbrNm); |
|
293 |
+ this.$store.commit("setRoles", userInfo.roles); |
|
291 | 294 |
|
292 | 295 |
// localStorage 저장 |
293 |
- localStorage.setItem("loginMode", loginMode); |
|
294 |
- localStorage.setItem("mbrId", userInfo.mbrId); |
|
295 |
- localStorage.setItem("mbrNm", userInfo.mbrNm); |
|
296 |
- localStorage.setItem("roles", JSON.stringify(userInfo.roles)); |
|
296 |
+ // localStorage.setItem("loginMode", loginMode); |
|
297 |
+ // localStorage.setItem("mbrId", userInfo.mbrId); |
|
298 |
+ // localStorage.setItem("mbrNm", userInfo.mbrNm); |
|
299 |
+ // localStorage.setItem("roles", JSON.stringify(userInfo.roles)); |
|
297 | 300 |
|
298 |
- if (token) { |
|
299 |
- localStorage.setItem("authorization", token); |
|
300 |
- } else { |
|
301 |
- localStorage.removeItem("authorization"); |
|
302 |
- } |
|
301 |
+ // if (token) { |
|
302 |
+ // localStorage.setItem("authorization", token); |
|
303 |
+ // } else { |
|
304 |
+ // localStorage.removeItem("authorization"); |
|
305 |
+ // } |
|
303 | 306 |
}, |
304 | 307 |
|
305 | 308 |
// ========== 로그인 성공 후 처리 ========== |
306 | 309 |
async handleLoginSuccess() { |
307 |
- const isAdmin = store.state.roles.some(role => role.authority === "ROLE_ADMIN"); |
|
310 |
+ const isAdmin = this.$store.state.roles.some(role => role.authority === "ROLE_ADMIN"); |
|
308 | 311 |
let redirectUrl = this.restoreRedirect("redirect") |
309 | 312 |
// 리다이렉트 URL 정리 |
310 | 313 |
if (redirectUrl && this.shouldRedirectToMain(redirectUrl)) { |
311 | 314 |
redirectUrl = this.$filters.ctxPath("/"); |
312 | 315 |
} |
313 | 316 |
// Context Path 처리 |
314 |
- if (redirectUrl && !redirectUrl.startsWith(store.state.contextPath) && store.state.contextPath) { |
|
317 |
+ if (redirectUrl && !redirectUrl.startsWith(this.$store.state.contextPath) && this.$store.state.contextPath) { |
|
315 | 318 |
redirectUrl = this.$filters.ctxPath(redirectUrl); |
316 | 319 |
} |
317 | 320 |
|
--- 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 store from "../AppStore"; |
|
77 |
+// import store from "../AppStore"; |
|
78 | 78 |
import { loginProc, getUserInfo, oauthLogin } from "../../../resources/api/login"; |
79 | 79 |
import { check2ndAuthProc, sendAuthEmailProc } from "../../../resources/api/email"; |
80 | 80 |
import queryParams from "../../../resources/js/queryParams"; |
... | ... | @@ -86,7 +86,7 @@ |
86 | 86 |
return { |
87 | 87 |
isLoading: false, |
88 | 88 |
member: { lgnId: null, pswd: null, lgnReqPage: 'U' }, |
89 |
- store: useStore(), |
|
89 |
+ // store: useStore(), |
|
90 | 90 |
isAdminPage: false, |
91 | 91 |
isOAuthLoading: false, |
92 | 92 |
memberInfo: { email: '', code: '' }, |
... | ... | @@ -251,10 +251,10 @@ |
251 | 251 |
|
252 | 252 |
try { |
253 | 253 |
// 기존 시스템 로그인 모드 따라가기 |
254 |
- const finalLoginMode = loginMode || store.state.loginMode || localStorage.getItem('loginMode') || 'J'; |
|
254 |
+ const finalLoginMode = loginMode || this.$store.state.loginMode || localStorage.getItem('loginMode') || 'J'; |
|
255 | 255 |
|
256 |
- store.commit("setLoginMode", finalLoginMode); |
|
257 |
- localStorage.setItem("loginMode", finalLoginMode); |
|
256 |
+ this.$store.commit("setLoginMode", finalLoginMode); |
|
257 |
+ // localStorage.setItem("loginMode", finalLoginMode); |
|
258 | 258 |
|
259 | 259 |
if (finalLoginMode === 'J') { |
260 | 260 |
await this.handleOAuthJWT(); |
... | ... | @@ -351,39 +351,39 @@ |
351 | 351 |
setAuthInfo(loginMode, token, userInfo) { |
352 | 352 |
// Store 설정 |
353 | 353 |
try { |
354 |
- if (typeof store !== 'undefined' && store.commit) { |
|
355 |
- store.commit("setLoginMode", loginMode); |
|
356 |
- store.commit("setAuthorization", token); |
|
357 |
- store.commit("setMbrId", userInfo.mbrId); |
|
358 |
- store.commit("setMbrNm", userInfo.mbrNm); |
|
359 |
- store.commit("setRoles", userInfo.roles); |
|
354 |
+ if (typeof this.$store !== 'undefined' && this.$store.commit) { |
|
355 |
+ this.$store.commit("setLoginMode", loginMode); |
|
356 |
+ this.$store.commit("setAuthorization", token); |
|
357 |
+ this.$store.commit("setMbrId", userInfo.mbrId); |
|
358 |
+ this.$store.commit("setMbrNm", userInfo.mbrNm); |
|
359 |
+ this.$store.commit("setRoles", userInfo.roles); |
|
360 | 360 |
} |
361 | 361 |
} catch (e) { |
362 | 362 |
console.warn("store 설정 실패, localStorage만 사용:", e); |
363 | 363 |
} |
364 | 364 |
|
365 | 365 |
// localStorage 저장 |
366 |
- localStorage.setItem("loginMode", loginMode); |
|
367 |
- localStorage.setItem("mbrId", userInfo.mbrId); |
|
368 |
- localStorage.setItem("mbrNm", userInfo.mbrNm); |
|
369 |
- localStorage.setItem("roles", JSON.stringify(userInfo.roles)); |
|
366 |
+ // localStorage.setItem("loginMode", loginMode); |
|
367 |
+ // localStorage.setItem("mbrId", userInfo.mbrId); |
|
368 |
+ // localStorage.setItem("mbrNm", userInfo.mbrNm); |
|
369 |
+ // localStorage.setItem("roles", JSON.stringify(userInfo.roles)); |
|
370 | 370 |
|
371 |
- if (token && loginMode === 'J') { |
|
372 |
- localStorage.setItem("authorization", token); |
|
373 |
- } else { |
|
374 |
- localStorage.removeItem("authorization"); |
|
375 |
- } |
|
371 |
+ // if (token && loginMode === 'J') { |
|
372 |
+ // localStorage.setItem("authorization", token); |
|
373 |
+ // } else { |
|
374 |
+ // localStorage.removeItem("authorization"); |
|
375 |
+ // } |
|
376 | 376 |
}, |
377 | 377 |
|
378 | 378 |
async handleLoginSuccess() { |
379 |
- const isAdmin = store.state.roles.some(role => role.authority === "ROLE_ADMIN"); |
|
379 |
+ const isAdmin = this.$store.state.roles.some(role => role.authority === "ROLE_ADMIN"); |
|
380 | 380 |
let redirectUrl = this.restoreRedirect("redirect") || sessionStorage.getItem('oauth_redirect'); |
381 | 381 |
|
382 | 382 |
if (redirectUrl && this.shouldRedirectToMain(redirectUrl)) { |
383 | 383 |
redirectUrl = this.$filters.ctxPath("/"); |
384 | 384 |
} |
385 | 385 |
|
386 |
- if (redirectUrl && !redirectUrl.startsWith(store.state.contextPath) && store.state.contextPath) { |
|
386 |
+ if (redirectUrl && !redirectUrl.startsWith(this.$store.state.contextPath) && this.$store.state.contextPath) { |
|
387 | 387 |
redirectUrl = this.$filters.ctxPath(redirectUrl); |
388 | 388 |
} |
389 | 389 |
|
--- client/views/pages/user/portal/main/Main.vue
+++ client/views/pages/user/portal/main/Main.vue
... | ... | @@ -212,7 +212,6 @@ |
212 | 212 |
|
213 | 213 |
<script> |
214 | 214 |
import ClusteredColumnChart from "../../../../component/chart/ClusteredColumnChart.vue"; |
215 |
- import store from "../../../AppStore.js"; |
|
216 | 215 |
|
217 | 216 |
// 통합검색 관련 |
218 | 217 |
import queryParams from "../../../../../resources/js/queryParams.js"; |
... | ... | @@ -262,9 +261,9 @@ |
262 | 261 |
} |
263 | 262 |
], |
264 | 263 |
search: { ...defaultTotalSearchParams }, |
265 |
- mbrId: store.state.mbrId || null, // 사용자 아이디 |
|
266 |
- roles: store.state.roles.map((auth) => auth.authority) || [], // 사용자 권한 |
|
267 |
- menuType: store.state.userType || null, // 메뉴 타입 |
|
264 |
+ mbrId: this.$store.state.mbrId || null, // 사용자 아이디 |
|
265 |
+ roles: this.$store.state.roles.map((auth) => auth.authority) || [], // 사용자 권한 |
|
266 |
+ menuType: this.$store.state.userType || null, // 메뉴 타입 |
|
268 | 267 |
|
269 | 268 |
// 공지사항 top5 |
270 | 269 |
noticeTop5: [], |
--- client/views/pages/user/portal/search/Search.vue
+++ client/views/pages/user/portal/search/Search.vue
... | ... | @@ -254,7 +254,6 @@ |
254 | 254 |
|
255 | 255 |
<script> |
256 | 256 |
import { toRaw } from 'vue' |
257 |
-import store from "../../../AppStore"; |
|
258 | 257 |
import queryParams from '../../../../../resources/js/queryParams'; |
259 | 258 |
import { defaultTotalSearchParams } from "../../../../../resources/js/defaultTotalSearchParams.js" |
260 | 259 |
import { searchAll } from "../../../../../resources/api/search.js"; |
... | ... | @@ -267,9 +266,9 @@ |
267 | 266 |
return { |
268 | 267 |
search: { ...defaultTotalSearchParams }, |
269 | 268 |
pageSearch: { ...defaultSearchParams }, |
270 |
- mbrId: store.state.mbrId || null, // 사용자 아이디 |
|
271 |
- roles: store.state.roles.map(auth => auth.authority) || [], // 사용자 권한 |
|
272 |
- menuType: store.state.userType || null, // 메뉴 타입 |
|
269 |
+ mbrId: this.$store.state.mbrId || null, // 사용자 아이디 |
|
270 |
+ roles: this.$store.state.roles.map(auth => auth.authority) || [], // 사용자 권한 |
|
271 |
+ menuType: this.$store.state.userType || null, // 메뉴 타입 |
|
273 | 272 |
inputSearchText: '', |
274 | 273 |
totalCount: 0, |
275 | 274 |
menuCount: 0, |
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?