

250613 김혜민 컬럼 행안부표준화 변경
@f46fb28acb970c5b81ebfb75d8df19d98920d4fa
--- client/resources/api/loginPolicy.js
+++ client/resources/api/loginPolicy.js
... | ... | @@ -32,6 +32,11 @@ |
32 | 32 |
return apiClient.post(`/admin/loginPolicy/saveStorageMode.json`, storageMode); |
33 | 33 |
} |
34 | 34 |
|
35 |
+// 전체 사용자 로그아웃 API 추가 |
|
36 |
+export const logoutAllUsers = () => { |
|
37 |
+ return apiClient.post(`/mbr/logoutAll.json`); |
|
38 |
+} |
|
39 |
+ |
|
35 | 40 |
/** 초기 세팅용 */ |
36 | 41 |
export const getLoginMode = () => { |
37 | 42 |
return apiClient.post(`/sys/loginPolicy/getLoginMode.json`); |
--- client/resources/js/defaultMenuSatisfactionParams.js
+++ client/resources/js/defaultMenuSatisfactionParams.js
... | ... | @@ -1,11 +1,11 @@ |
1 | 1 |
// 관리자 정보 객체 |
2 | 2 |
const defaultMenuDgstfnParams = { |
3 | 3 |
menuId: '', |
4 |
- rspnsFive: 'N', |
|
5 |
- rspnsFour: 'N', |
|
6 |
- rspnsThree: 'N', |
|
7 |
- rspnsTwo: 'N', |
|
8 |
- rspnsOne: 'N', |
|
4 |
+ rspns5: 'N', |
|
5 |
+ rspns4: 'N', |
|
6 |
+ rspns3: 'N', |
|
7 |
+ rspns2: 'N', |
|
8 |
+ rspns1: 'N', |
|
9 | 9 |
opnn: '', |
10 | 10 |
}; |
11 | 11 |
|
--- client/views/layout/AdminHeader.vue
+++ client/views/layout/AdminHeader.vue
... | ... | @@ -83,7 +83,7 @@ |
83 | 83 |
} |
84 | 84 |
|
85 | 85 |
// if (route.meta.typeId.includes("BBS_MNG")) { |
86 |
- // const matchedMenu = store.state.flatMenuList.find(menu => menu.menuTypeCtgry === route.meta.typeId); |
|
86 |
+ // const matchedMenu = store.state.flatMenuList.find(menu => menu.menuTypeArtcl === route.meta.typeId); |
|
87 | 87 |
// if (matchedMenu) { |
88 | 88 |
// return matchedMenu.menuNm; |
89 | 89 |
// } |
--- client/views/pages/AppRouter.js
+++ client/views/pages/AppRouter.js
... | ... | @@ -57,10 +57,10 @@ |
57 | 57 |
const res = await findAll(); |
58 | 58 |
if (res.status == 200) { |
59 | 59 |
const newRoutes = res.data.data.map(route => ({ |
60 |
- path: route.pageCrs, |
|
60 |
+ path: route.userPagePath, |
|
61 | 61 |
name: route.contsEngNm, |
62 | 62 |
korName: route.contsKornNm, |
63 |
- component: () => import(`${route.compnCrs}`), |
|
63 |
+ component: () => import(`${route.compnPath}`), |
|
64 | 64 |
meta: { authrt: route.authrtList, typeId: route.contsId, korName: route.contsKornNm } |
65 | 65 |
})); |
66 | 66 |
return newRoutes; |
--- client/views/pages/adm/boardManagement/boardManagement/BoardManagementInsert.vue
+++ client/views/pages/adm/boardManagement/boardManagement/BoardManagementInsert.vue
... | ... | @@ -15,7 +15,7 @@ |
15 | 15 |
</div> |
16 | 16 |
<div class="layout"> |
17 | 17 |
<label class="form-title">게시판 상단 정보</label> |
18 |
- <input type="text" class="form-control sm" v-model="bbsMng.bbsUpInfo" |
|
18 |
+ <input type="text" class="form-control sm" v-model="bbsMng.bbsUpendInfo" |
|
19 | 19 |
placeholder="게시판 상단에 표기될 정보를 입력해주세요." /> |
20 | 20 |
</div> |
21 | 21 |
<div class="layout"> |
... | ... | @@ -41,7 +41,7 @@ |
41 | 41 |
</div> |
42 | 42 |
<div class="layout"> |
43 | 43 |
<label class="form-title"><span>*</span>페이지 유형</label> |
44 |
- <select name="" id="" class="form-select sm" v-model="bbsMng.cd"> |
|
44 |
+ <select name="" id="" class="form-select sm" v-model="bbsMng.pageType"> |
|
45 | 45 |
<option :value="null" disabled>선택하세요</option> |
46 | 46 |
<option v-for="(item, idx) in pageTypeList" :value="item.cd" :key="idx"> |
47 | 47 |
{{ item.cdNm }} |
... | ... | @@ -346,7 +346,7 @@ |
346 | 346 |
alert("목록 개수는 1 이상을 입력하세요."); |
347 | 347 |
return false; |
348 | 348 |
} |
349 |
- if (this.bbsMng.cd == null || this.bbsMng.cd == "") { |
|
349 |
+ if (this.bbsMng.pageType == null || this.bbsMng.pageType == "") { |
|
350 | 350 |
alert("페이지 유형을 선택하세요."); |
351 | 351 |
return false; |
352 | 352 |
} |
--- client/views/pages/adm/boardManagement/boardManagement/BoardManagementSelectListOne.vue
+++ client/views/pages/adm/boardManagement/boardManagement/BoardManagementSelectListOne.vue
... | ... | @@ -21,11 +21,11 @@ |
21 | 21 |
</div> |
22 | 22 |
<div class="layout"> |
23 | 23 |
<p class="form-title">게시판 상단 정보</p> |
24 |
- <p>{{bbsMng.bbsUpInfo}}</p> |
|
24 |
+ <p>{{bbsMng.bbsUpendInfo}}</p> |
|
25 | 25 |
<!-- <input |
26 | 26 |
type="text" |
27 | 27 |
class="full-input" |
28 |
- v-model="bbsMng.bbsUpInfo" |
|
28 |
+ v-model="bbsMng.bbsUpendInfo" |
|
29 | 29 |
disabled |
30 | 30 |
/> --> |
31 | 31 |
</div> |
... | ... | @@ -78,7 +78,7 @@ |
78 | 78 |
name="" |
79 | 79 |
id="" |
80 | 80 |
class="full-select" |
81 |
- v-model="bbsMng.cd" |
|
81 |
+ v-model="bbsMng.pageType" |
|
82 | 82 |
disabled |
83 | 83 |
> |
84 | 84 |
<option :value="null" disabled>선택해주세요</option> |
... | ... | @@ -378,8 +378,8 @@ |
378 | 378 |
watch: {}, |
379 | 379 |
computed: { |
380 | 380 |
pageTypeName() { |
381 |
- const match = this.pageTypeList.find(item => item.cd === this.bbsMng.cd); |
|
382 |
- return match ? match.cdNm : this.bbsMng.cd; |
|
381 |
+ const match = this.pageTypeList.find(item => item.cd === this.bbsMng.pageType); |
|
382 |
+ return match ? match.cdNm : this.bbsMng.pageType; |
|
383 | 383 |
} |
384 | 384 |
}, |
385 | 385 |
components: {}, |
--- client/views/pages/adm/boardManagement/wordsManagement/WordsManagementSelectList.vue
+++ client/views/pages/adm/boardManagement/wordsManagement/WordsManagementSelectList.vue
... | ... | @@ -177,11 +177,11 @@ |
177 | 177 |
}, |
178 | 178 |
// 삭제할 워드 선택 |
179 | 179 |
handleSelect(row, idx) { |
180 |
- let cntrlNmId = this.list[idx]["cntrlNmId"]; |
|
181 |
- if (this.delWords.includes(cntrlNmId)) { |
|
182 |
- this.delWords = this.delWords.filter((word) => word !== cntrlNmId); |
|
180 |
+ let phwrdId = this.list[idx]["phwrdId"]; |
|
181 |
+ if (this.delWords.includes(phwrdId)) { |
|
182 |
+ this.delWords = this.delWords.filter((word) => word !== phwrdId); |
|
183 | 183 |
} else { |
184 |
- this.delWords.push(cntrlNmId); |
|
184 |
+ this.delWords.push(phwrdId); |
|
185 | 185 |
} |
186 | 186 |
}, |
187 | 187 |
// 삭제 버튼 로직 |
... | ... | @@ -228,7 +228,7 @@ |
228 | 228 |
this.tbody = this.list.map((word, idx) => ({ |
229 | 229 |
// id: this.getNotice(bbsMng, idx), // 번호 |
230 | 230 |
id: this.listCnt - idx - (this.search.currentPage - 1) * this.search.recordSize, // 번호 |
231 |
- bbsNm: word.cntrlNm, // 제목 |
|
231 |
+ bbsNm: word.phwrd, // 제목 |
|
232 | 232 |
wrtrNm: word.rgtrNm, // 작성자 |
233 | 233 |
wrtDt: word.regDt, // 작성일 |
234 | 234 |
})); |
--- client/views/pages/adm/log/LoginLog.vue
+++ client/views/pages/adm/log/LoginLog.vue
... | ... | @@ -139,7 +139,7 @@ |
139 | 139 |
: null, |
140 | 140 |
lgnId: lgnHstry.lgnId, |
141 | 141 |
cntnIp: lgnHstry.cntnIp, |
142 |
- cntnOperSys: lgnHstry.cntnOperSys, |
|
142 |
+ cntnOperSysm: lgnHstry.cntnOperSysm, |
|
143 | 143 |
})); |
144 | 144 |
}, |
145 | 145 |
|
--- client/views/pages/adm/main/Main.vue
+++ client/views/pages/adm/main/Main.vue
... | ... | @@ -201,7 +201,7 @@ |
201 | 201 |
let newData = {}; |
202 | 202 |
newData["date"] = data["dates"]; |
203 | 203 |
for (let i = 0; i < data["authrt_nm"].length; i++) { |
204 |
- newData[data["authrt_nm"][i]] = data["cntn_nope"][i]; |
|
204 |
+ newData[data["authrt_nm"][i]] = data["acsr_cnt"][i]; |
|
205 | 205 |
} |
206 | 206 |
datas.push(newData); |
207 | 207 |
} |
... | ... | @@ -266,7 +266,7 @@ |
266 | 266 |
let depth1 = this.findMenu(this.menuList, "MENU_000000000000010"); |
267 | 267 |
this.$store.commit("setMenu", depth1); |
268 | 268 |
for (let menu of depth1.childList) { |
269 |
- if (menu.menuTypeCtgry == this.bbsCnList[idx]["id"]) { |
|
269 |
+ if (menu.menuTypeArtcl == this.bbsCnList[idx]["id"]) { |
|
270 | 270 |
await this.cntnStatsSave(menu.menuId); |
271 | 271 |
} |
272 | 272 |
} |
--- client/views/pages/adm/member/userManagement/UserManagementSelectList.vue
+++ client/views/pages/adm/member/userManagement/UserManagementSelectList.vue
... | ... | @@ -137,7 +137,7 @@ |
137 | 137 |
inqTrprId: null, |
138 | 138 |
inqRsn: null, |
139 | 139 |
inqIp: null, |
140 |
- rdr: null, |
|
140 |
+ inqpr: null, |
|
141 | 141 |
inqDt: null, |
142 | 142 |
}, |
143 | 143 |
}; |
... | ... | @@ -226,7 +226,7 @@ |
226 | 226 |
inqTrprId: null, |
227 | 227 |
inqRsn: null, |
228 | 228 |
inqIp: null, |
229 |
- rdr: null, |
|
229 |
+ inqpr: null, |
|
230 | 230 |
inqDt: null, |
231 | 231 |
}; |
232 | 232 |
}, |
--- client/views/pages/adm/preferences/contentTypeManagement/ContentTypeManagementInsert.vue
+++ client/views/pages/adm/preferences/contentTypeManagement/ContentTypeManagementInsert.vue
... | ... | @@ -40,8 +40,8 @@ |
40 | 40 |
<input |
41 | 41 |
type="text" |
42 | 42 |
class="form-control sm" |
43 |
- v-model="contsTypeVO.mngrPageCrs" |
|
44 |
- ref="mngrPageCrs" |
|
43 |
+ v-model="contsTypeVO.mngrPagePath" |
|
44 |
+ ref="mngrPagePath" |
|
45 | 45 |
placeholder="관리자 path를 입력하세요." |
46 | 46 |
/> |
47 | 47 |
<span><strong>관리자 PATH</strong> 또는 <strong>사용자 PATH</strong> 중 하나는 필수입니다.</span> |
... | ... | @@ -54,8 +54,8 @@ |
54 | 54 |
<input |
55 | 55 |
type="text" |
56 | 56 |
class="form-control sm" |
57 |
- v-model="contsTypeVO.pageCrs" |
|
58 |
- ref="pageCrs" |
|
57 |
+ v-model="contsTypeVO.userPagePath" |
|
58 |
+ ref="userPagePath" |
|
59 | 59 |
placeholder="사용자 path를 입력하세요." |
60 | 60 |
/> |
61 | 61 |
</div> |
... | ... | @@ -66,8 +66,8 @@ |
66 | 66 |
<input |
67 | 67 |
type="text" |
68 | 68 |
class="form-control sm" |
69 |
- v-model="contsTypeVO.compnCrs" |
|
70 |
- ref="compnCrs" |
|
69 |
+ v-model="contsTypeVO.compnPath" |
|
70 |
+ ref="compnPath" |
|
71 | 71 |
placeholder="COMPONENT URL을 입력하세요." |
72 | 72 |
/> |
73 | 73 |
</div> |
... | ... | @@ -212,50 +212,50 @@ |
212 | 212 |
this.contsTypeVO.contsEngNm = contsEngNm; |
213 | 213 |
|
214 | 214 |
// 관리자 PATH 혹은 사용자 PATH 중 최소 1개 이상 작성 여부 |
215 |
- let mngrPageCrs = this.contsTypeVO.mngrPageCrs?.trim(); |
|
216 |
- let pageCrs = this.contsTypeVO.pageCrs?.trim(); |
|
217 |
- if (this.isEmpty(mngrPageCrs) && this.isEmpty(pageCrs)) { |
|
215 |
+ let mngrPagePath = this.contsTypeVO.mngrPagePath?.trim(); |
|
216 |
+ let userPagePath = this.contsTypeVO.userPagePath?.trim(); |
|
217 |
+ if (this.isEmpty(mngrPagePath) && this.isEmpty(userPagePath)) { |
|
218 | 218 |
alert("관리자 PATH 혹은 사용자 PATH를 입력하세요."); |
219 | 219 |
return false; |
220 | 220 |
} |
221 |
- this.contsTypeVO.mngrPageCrs = mngrPageCrs; |
|
222 |
- this.contsTypeVO.pageCrs = pageCrs; |
|
221 |
+ this.contsTypeVO.mngrPagePath = mngrPagePath; |
|
222 |
+ this.contsTypeVO.userPagePath = userPagePath; |
|
223 | 223 |
|
224 | 224 |
const pageCrsRegex = /^\/(?:[a-zA-Z0-9_\-]+\/)*[a-zA-Z0-9_\-]+\.[a-zA-Z0-9]+$/; |
225 | 225 |
const notFound = '/cmmn/notfound.page'; |
226 |
- if (!this.isEmpty(mngrPageCrs)) { |
|
227 |
- if (!pageCrsRegex.test(this.contsTypeVO.mngrPageCrs)) { |
|
226 |
+ if (!this.isEmpty(mngrPagePath)) { |
|
227 |
+ if (!pageCrsRegex.test(this.contsTypeVO.mngrPagePath)) { |
|
228 | 228 |
alert("관리자 PATH는 /로 시작하고, 마지막에 확장자가 포함되어야 합니다."); |
229 |
- this.$refs.mngrPageCrs.focus(); |
|
229 |
+ this.$refs.mngrPagePath.focus(); |
|
230 | 230 |
return false; |
231 | 231 |
} |
232 |
- if(this.contsTypeVO.mngrPageCrs.toLowerCase() == notFound) { |
|
232 |
+ if(this.contsTypeVO.mngrPagePath.toLowerCase() == notFound) { |
|
233 | 233 |
alert("사용할 수 없는 경로입니다."); |
234 |
- this.$refs.mngrPageCrs.focus(); |
|
234 |
+ this.$refs.mngrPagePath.focus(); |
|
235 | 235 |
return false; |
236 | 236 |
} |
237 | 237 |
} |
238 |
- if (!this.isEmpty(pageCrs)) { |
|
239 |
- if (!pageCrsRegex.test(this.contsTypeVO.pageCrs)) { |
|
238 |
+ if (!this.isEmpty(userPagePath)) { |
|
239 |
+ if (!pageCrsRegex.test(this.contsTypeVO.userPagePath)) { |
|
240 | 240 |
alert("사용자 PATH는 /로 시작하고, 마지막에 확장자가 포함되어야 합니다."); |
241 |
- this.$refs.pageCrs.focus(); |
|
241 |
+ this.$refs.userPagePath.focus(); |
|
242 | 242 |
return false; |
243 | 243 |
} |
244 |
- if(this.contsTypeVO.pageCrs.toLowerCase() == notFound) { |
|
244 |
+ if(this.contsTypeVO.userPagePath.toLowerCase() == notFound) { |
|
245 | 245 |
alert("사용할 수 없는 경로입니다."); |
246 |
- this.$refs.pageCrs.focus(); |
|
246 |
+ this.$refs.userPagePath.focus(); |
|
247 | 247 |
return false; |
248 | 248 |
} |
249 | 249 |
} |
250 | 250 |
|
251 | 251 |
// COMPONENT_URL |
252 |
- let compnCrs = this.contsTypeVO.compnCrs?.trim(); |
|
253 |
- if (this.isEmpty(compnCrs)) { |
|
252 |
+ let compnPath = this.contsTypeVO.compnPath?.trim(); |
|
253 |
+ if (this.isEmpty(compnPath)) { |
|
254 | 254 |
alert("COMPONENT_URL을 입력하세요."); |
255 |
- this.$refs.compnCrs.focus(); |
|
255 |
+ this.$refs.compnPath.focus(); |
|
256 | 256 |
return false; |
257 | 257 |
} |
258 |
- this.contsTypeVO.compnCrs = compnCrs; |
|
258 |
+ this.contsTypeVO.compnPath = compnPath; |
|
259 | 259 |
|
260 | 260 |
// 메뉴노출 |
261 | 261 |
if (this.isEmpty(this.contsTypeVO.expsrYn)) { |
--- client/views/pages/adm/preferences/contentTypeManagement/ContentTypeManagementSelectListOne.vue
+++ client/views/pages/adm/preferences/contentTypeManagement/ContentTypeManagementSelectListOne.vue
... | ... | @@ -29,31 +29,31 @@ |
29 | 29 |
</div> |
30 | 30 |
<div class="layout"> |
31 | 31 |
<p class="form-title">관리자 PATH</p> |
32 |
- <p>{{ contsTypeVO.mngrPageCrs }}</p> |
|
32 |
+ <p>{{ contsTypeVO.mngrPagePath }}</p> |
|
33 | 33 |
<!-- <input |
34 | 34 |
type="text" |
35 | 35 |
class="full-input" |
36 |
- v-model="contsTypeVO.mngrPageCrs" |
|
36 |
+ v-model="contsTypeVO.mngrPagePath" |
|
37 | 37 |
disabled |
38 | 38 |
/> --> |
39 | 39 |
</div> |
40 | 40 |
<div class="layout"> |
41 | 41 |
<p class="form-title">사용자 PATH</p> |
42 |
- <p>{{ contsTypeVO.pageCrs }}</p> |
|
42 |
+ <p>{{ contsTypeVO.userPagePath }}</p> |
|
43 | 43 |
<!-- <input |
44 | 44 |
type="text" |
45 | 45 |
class="full-input" |
46 |
- v-model="contsTypeVO.pageCrs" |
|
46 |
+ v-model="contsTypeVO.userPagePath" |
|
47 | 47 |
disabled |
48 | 48 |
/> --> |
49 | 49 |
</div> |
50 | 50 |
<div class="layout"> |
51 | 51 |
<p class="form-title">COMPONENT_URL</p> |
52 |
- <p>{{ contsTypeVO.compnCrs }}</p> |
|
52 |
+ <p>{{ contsTypeVO.compnPath }}</p> |
|
53 | 53 |
<!-- <input |
54 | 54 |
type="text" |
55 | 55 |
class="full-input" |
56 |
- v-model="contsTypeVO.compnCrs" |
|
56 |
+ v-model="contsTypeVO.compnPath" |
|
57 | 57 |
disabled |
58 | 58 |
/> --> |
59 | 59 |
</div> |
--- client/views/pages/adm/statistics/BbsStatistics.vue
+++ client/views/pages/adm/statistics/BbsStatistics.vue
... | ... | @@ -173,7 +173,7 @@ |
173 | 173 |
newData["menu"] = data["bbs_nm"]; |
174 | 174 |
this.authrtNmList = data["authrt_nm"]; |
175 | 175 |
for (let i = 0; i < data["authrt_nm"].length; i++) { |
176 |
- newData[data["authrt_nm"][i]] = data["cntn_nope"][i]; |
|
176 |
+ newData[data["authrt_nm"][i]] = data["acsr_cnt"][i]; |
|
177 | 177 |
} |
178 | 178 |
datas.push(newData); |
179 | 179 |
} |
--- client/views/pages/adm/statistics/MenuStatistics.vue
+++ client/views/pages/adm/statistics/MenuStatistics.vue
... | ... | @@ -174,7 +174,7 @@ |
174 | 174 |
newData["menu"] = data["menu_name"]; |
175 | 175 |
this.authrtNmList = data["authrt_nm"]; |
176 | 176 |
for (let i = 0; i < data["authrt_nm"].length; i++) { |
177 |
- newData[data["authrt_nm"][i]] = data["cntn_nope"][i]; |
|
177 |
+ newData[data["authrt_nm"][i]] = data["acsr_cnt"][i]; |
|
178 | 178 |
} |
179 | 179 |
datas.push(newData); |
180 | 180 |
} |
--- client/views/pages/adm/statistics/UserStatistics.vue
+++ client/views/pages/adm/statistics/UserStatistics.vue
... | ... | @@ -162,7 +162,7 @@ |
162 | 162 |
newData["date"] = data["dates"]; |
163 | 163 |
this.authrtNmList = data["authrt_nm"]; |
164 | 164 |
for (let i = 0; i < data["authrt_nm"].length; i++) { |
165 |
- newData[data["authrt_nm"][i]] = data["cntn_nope"][i]; |
|
165 |
+ newData[data["authrt_nm"][i]] = data["acsr_cnt"][i]; |
|
166 | 166 |
} |
167 | 167 |
datas.push(newData); |
168 | 168 |
} |
--- client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
+++ client/views/pages/adm/system/LoginPolicy/LoginPolicy.vue
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 |
<div open class="form-box"> |
6 | 6 |
<div class="form-box-title"> |
7 | 7 |
<p>기본정보</p> |
8 |
- <p><span>*</span>로그인 정책을 변경하면 전체 사용자가 로그아웃됩니다.</p> |
|
8 |
+ <p><span>*</span>시스템 정책을 변경하면 전체 사용자가 로그아웃됩니다.</p> |
|
9 | 9 |
</div> |
10 | 10 |
<div class="form-content"> |
11 | 11 |
<div class="layout"> |
... | ... | @@ -23,7 +23,6 @@ |
23 | 23 |
<label for="allowMultipleLoginN">비허용</label> |
24 | 24 |
</div> |
25 | 25 |
</div> |
26 |
- <!-- <p>{{ allowMultipleLogin ? '중복 로그인을 허용하고 있습니다.' : '중복 로그인을 허용하지 않습니다.' }}</p>--> |
|
27 | 26 |
</div> |
28 | 27 |
</div> |
29 | 28 |
<div class="layout border-bottom"> |
... | ... | @@ -41,9 +40,6 @@ |
41 | 40 |
<label for="loginModeS">SESSION 방식</label> |
42 | 41 |
</div> |
43 | 42 |
</div> |
44 |
- <!-- <span class="ml10 gray"> |
|
45 |
- 현재 로그인 방식은 <strong>{{ loginModeLabel }}</strong> 입니다. |
|
46 |
- </span> --> |
|
47 | 43 |
</div> |
48 | 44 |
</div> |
49 | 45 |
<div class="layout"> |
... | ... | @@ -51,19 +47,16 @@ |
51 | 47 |
<div class="form-group"> |
52 | 48 |
<div class="check-area"> |
53 | 49 |
<div class="form-check"> |
54 |
- <input type="radio" id="storageModeL" class="mr5" value="L" v-model="strgMode" |
|
50 |
+ <input type="radio" id="storageModeL" class="mr5" value="L" v-model="strgMth" |
|
55 | 51 |
@change="saveByStorageMode" /> |
56 | 52 |
<label for="storageModeL">LOCAL 방식</label> |
57 | 53 |
</div> |
58 | 54 |
<div class="form-check"> |
59 |
- <input type="radio" id="storageModeS" class="mr5" value="S" v-model="strgMode" |
|
55 |
+ <input type="radio" id="storageModeS" class="mr5" value="S" v-model="strgMth" |
|
60 | 56 |
@change="saveByStorageMode" /> |
61 | 57 |
<label for="storageModeS">SESSION 방식</label> |
62 | 58 |
</div> |
63 | 59 |
</div> |
64 |
- <!-- <span class="ml10 gray"> |
|
65 |
- 현재 로그인 방식은 <strong>{{ loginModeLabel }}</strong> 입니다. |
|
66 |
- </span> --> |
|
67 | 60 |
</div> |
68 | 61 |
</div> |
69 | 62 |
<div class="layout"> |
... | ... | @@ -81,7 +74,6 @@ |
81 | 74 |
<label for="use2ndAuthN">미사용</label> |
82 | 75 |
</div> |
83 | 76 |
</div> |
84 |
- <!-- <p>{{ allowMultipleLogin ? '중복 로그인을 허용하고 있습니다.' : '중복 로그인을 허용하지 않습니다.' }}</p>--> |
|
85 | 77 |
</div> |
86 | 78 |
</div> |
87 | 79 |
<div class="layout"> |
... | ... | @@ -106,9 +98,19 @@ |
106 | 98 |
</template> |
107 | 99 |
|
108 | 100 |
<script> |
109 |
-import { findAllByLoginPolicy, saveByLoginPolicy, findAllByLoginMode, saveByLoginMode, findAllBy2ndAuth, saveBy2ndAuth, findAllByStorageMode, saveByStorageMode } from '../../../../../resources/api/loginPolicy.js'; |
|
101 |
+import { |
|
102 |
+ findAllByLoginPolicy, |
|
103 |
+ saveByLoginPolicy, |
|
104 |
+ findAllByLoginMode, |
|
105 |
+ saveByLoginMode, |
|
106 |
+ findAllBy2ndAuth, |
|
107 |
+ saveBy2ndAuth, |
|
108 |
+ findAllByStorageMode, |
|
109 |
+ saveByStorageMode |
|
110 |
+} from '../../../../../resources/api/loginPolicy.js'; |
|
110 | 111 |
import { getCntxtPth, saveCntxtPth } from '../../../../../resources/api/cntxtPth'; |
111 | 112 |
import { cacheReSet } from "../../../../../resources/api/cacheReSet"; |
113 |
+ |
|
112 | 114 |
export default { |
113 | 115 |
data() { |
114 | 116 |
return { |
... | ... | @@ -133,23 +135,21 @@ |
133 | 135 |
}, |
134 | 136 |
mounted() { |
135 | 137 |
}, |
136 |
- computed: { |
|
137 |
- // loginModeLabel() { |
|
138 |
- // return this.lgnMode === 'J' ? 'JWT' : 'SESSION'; |
|
139 |
- // } |
|
140 |
- }, |
|
141 | 138 |
methods: { |
142 | 139 |
async findAll() { |
143 | 140 |
try { |
144 | 141 |
const res1 = await findAllByLoginPolicy(); |
145 | 142 |
this.allowMultipleLogin = res1.data.data === true ? 'Y' : 'N'; |
146 | 143 |
this.previousAllowMultipleLogin = this.allowMultipleLogin; |
144 |
+ |
|
147 | 145 |
const res2 = await findAllByLoginMode(); |
148 | 146 |
this.lgnMode = res2.data.data; |
149 | 147 |
this.previousLgnMode = this.lgnMode; // 초기 상태를 저장 |
148 |
+ |
|
150 | 149 |
const res3 = await findAllBy2ndAuth(); |
151 | 150 |
this.use2ndAuth = res3.data.data === true ? 'Y' : 'N'; |
152 | 151 |
this.previousUse2ndAuth = this.use2ndAuth; // 초기 상태를 저장 |
152 |
+ |
|
153 | 153 |
const res4 = await findAllByStorageMode(); |
154 | 154 |
this.strgMode = res4.data.data; |
155 | 155 |
this.previousStrgMode = this.strgMode; // 초기 상태를 저장 |
... | ... | @@ -157,6 +157,8 @@ |
157 | 157 |
alert('설정 정보를 불러오는 데 실패했습니다.'); |
158 | 158 |
} |
159 | 159 |
}, |
160 |
+ |
|
161 |
+ // 중복로그인 설정 저장 - 개선된 버전 |
|
160 | 162 |
async saveByLoginPolicy() { |
161 | 163 |
const confirmed = confirm( |
162 | 164 |
'로그인 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
... | ... | @@ -168,16 +170,24 @@ |
168 | 170 |
|
169 | 171 |
try { |
170 | 172 |
const loginPolicy = {}; |
171 |
- loginPolicy.allowMultipleLogin = this.allowMultipleLogin; |
|
173 |
+ loginPolicy.mltLgnPrmYn = this.allowMultipleLogin; |
|
172 | 174 |
await saveByLoginPolicy(loginPolicy); |
175 |
+ |
|
176 |
+ // 전체 사용자 로그아웃 API 호출 |
|
177 |
+ await this.performGlobalLogout(); |
|
178 |
+ |
|
173 | 179 |
alert('중복 로그인 설정이 저장되었습니다.'); |
174 |
- this.$store.commit("setStoreReset"); |
|
175 |
- window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
180 |
+ |
|
181 |
+ // 완전한 정리 후 로그인 페이지로 이동 |
|
182 |
+ await this.performCompleteCleanupAndRedirect(); |
|
183 |
+ |
|
176 | 184 |
} catch (err) { |
177 |
- alert('중복 로그인 설정 저장 실패'+ (err.response?.data?.message || err.message)); |
|
185 |
+ alert('중복 로그인 설정 저장 실패: ' + (err.response?.data?.message || err.message)); |
|
178 | 186 |
this.allowMultipleLogin = this.previousAllowMultipleLogin; |
179 | 187 |
} |
180 | 188 |
}, |
189 |
+ |
|
190 |
+ // 로그인 방식 저장 - 개선된 버전 |
|
181 | 191 |
async saveByLoginMode() { |
182 | 192 |
const confirmed = confirm( |
183 | 193 |
'로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
... | ... | @@ -191,23 +201,38 @@ |
191 | 201 |
const loginMode = {}; |
192 | 202 |
loginMode.lgnMode = this.lgnMode; |
193 | 203 |
await saveByLoginMode(loginMode); |
204 |
+ |
|
205 |
+ // 전체 사용자 로그아웃 API 호출 |
|
206 |
+ await this.performGlobalLogout(); |
|
207 |
+ |
|
194 | 208 |
alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
195 |
- this.$store.commit("setStoreReset"); |
|
196 |
- window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
209 |
+ |
|
210 |
+ // 완전한 정리 후 로그인 페이지로 이동 |
|
211 |
+ await this.performCompleteCleanupAndRedirect(); |
|
212 |
+ |
|
197 | 213 |
} catch (err) { |
198 | 214 |
alert('로그인 방식 저장 실패: ' + (err.response?.data?.message || err.message)); |
199 | 215 |
this.lgnMode = this.previousLgnMode; |
200 | 216 |
} |
201 | 217 |
}, |
202 | 218 |
|
203 |
- // 최신 Context Path 조회 |
|
204 |
- async findCntxtPth() { |
|
219 |
+ // 스토리지 방식 저장 - 개선된 버전 |
|
220 |
+ async saveByStorageMode() { |
|
221 |
+ const confirmed = confirm( |
|
222 |
+ '스토리지 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
|
223 |
+ ); |
|
224 |
+ if (!confirmed) { |
|
225 |
+ this.strgMode = this.previousStrgMode; |
|
226 |
+ return; |
|
227 |
+ } |
|
228 |
+ |
|
205 | 229 |
try { |
206 |
- const res = await getCntxtPth(); |
|
207 |
- if (res.status == 200) { |
|
208 |
- this.cntxtPth = res.data.data; |
|
209 |
- this.defaultCntxtPth = res.data.data; |
|
210 |
- } |
|
230 |
+ const storageMode = {}; |
|
231 |
+ storageMode.strgMth = this.strgMode; |
|
232 |
+ await saveByStorageMode(storageMode); |
|
233 |
+ alert('스토리지 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
|
234 |
+ this.$store.commit("setStoreReset"); |
|
235 |
+ window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
211 | 236 |
} catch (error) { |
212 | 237 |
const errorData = error.response.data; |
213 | 238 |
if (errorData.message != null && errorData.message != "") { |
... | ... | @@ -215,9 +240,9 @@ |
215 | 240 |
} else { |
216 | 241 |
alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
217 | 242 |
} |
243 |
+ this.strgMode = this.previousStrgMode; |
|
218 | 244 |
} |
219 | 245 |
}, |
220 |
- |
|
221 | 246 |
// Context Path 저장 |
222 | 247 |
async saveByContextPath() { |
223 | 248 |
if (!this.validation()) { |
... | ... | @@ -258,6 +283,49 @@ |
258 | 283 |
} |
259 | 284 |
} |
260 | 285 |
}, |
286 |
+ // 2차 인증 설정 저장 |
|
287 |
+ async saveBy2ndAuth() { |
|
288 |
+ const confirmed = confirm( |
|
289 |
+ '2차 인증 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
|
290 |
+ ); |
|
291 |
+ if (!confirmed) { |
|
292 |
+ this.use2ndAuth = this.previousUse2ndAuth; |
|
293 |
+ return; |
|
294 |
+ } |
|
295 |
+ |
|
296 |
+ try { |
|
297 |
+ const email2ndAuth = {}; |
|
298 |
+ email2ndAuth.useYn = this.use2ndAuth; |
|
299 |
+ await saveBy2ndAuth(email2ndAuth); |
|
300 |
+ alert('이메일 2차 인증 설정이 저장되었습니다.'); |
|
301 |
+ // this.$store.commit("setStoreReset"); |
|
302 |
+ // window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
303 |
+ } catch (error) { |
|
304 |
+ const errorData = error.response.data; |
|
305 |
+ if (errorData.message != null && errorData.message != "") { |
|
306 |
+ alert(error.response.data.message); |
|
307 |
+ } else { |
|
308 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
309 |
+ } |
|
310 |
+ } |
|
311 |
+ }, |
|
312 |
+ // 최신 Context Path 조회 |
|
313 |
+ async findCntxtPth() { |
|
314 |
+ try { |
|
315 |
+ const res = await getCntxtPth(); |
|
316 |
+ if (res.status == 200) { |
|
317 |
+ this.cntxtPth = res.data.data; |
|
318 |
+ this.defaultCntxtPth = res.data.data; |
|
319 |
+ } |
|
320 |
+ } catch (error) { |
|
321 |
+ const errorData = error.response?.data; |
|
322 |
+ if (errorData?.message != null && errorData?.message != "") { |
|
323 |
+ alert(error.response.data.message); |
|
324 |
+ } else { |
|
325 |
+ alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
326 |
+ } |
|
327 |
+ } |
|
328 |
+ }, |
|
261 | 329 |
|
262 | 330 |
// 유효성 검사 |
263 | 331 |
validation() { |
... | ... | @@ -285,60 +353,159 @@ |
285 | 353 |
return true; |
286 | 354 |
}, |
287 | 355 |
|
288 |
- // 2차 인증 설정 저장 |
|
289 |
- async saveBy2ndAuth() { |
|
290 |
- const confirmed = confirm( |
|
291 |
- '2차 인증 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
|
292 |
- ); |
|
293 |
- if (!confirmed) { |
|
294 |
- this.use2ndAuth = this.previousUse2ndAuth; |
|
295 |
- return; |
|
296 |
- } |
|
297 |
- |
|
356 |
+ // 전체 사용자 로그아웃 API 호출 |
|
357 |
+ async performGlobalLogout() { |
|
298 | 358 |
try { |
299 |
- const email2ndAuth = {}; |
|
300 |
- email2ndAuth.useYn = this.use2ndAuth; |
|
301 |
- await saveBy2ndAuth(email2ndAuth); |
|
302 |
- alert('이메일 2차 인증 설정이 저장되었습니다.'); |
|
303 |
- // this.$store.commit("setStoreReset"); |
|
304 |
- // window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
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 호출 완료'); |
|
305 | 368 |
} 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 |
- } |
|
369 |
+ console.warn('전체 로그아웃 API 호출 실패:', error); |
|
370 |
+ // 실패해도 계속 진행 |
|
312 | 371 |
} |
313 | 372 |
}, |
314 | 373 |
|
315 |
- // 스토리지 방식 저장 |
|
316 |
- async saveByStorageMode() { |
|
317 |
- const confirmed = confirm( |
|
318 |
- '스토리지 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?' |
|
319 |
- ); |
|
320 |
- if (!confirmed) { |
|
321 |
- this.strgMode = this.previousStrgMode; |
|
322 |
- return; |
|
323 |
- } |
|
324 |
- |
|
374 |
+ // 완전한 정리 및 리다이렉트 |
|
375 |
+ async performCompleteCleanupAndRedirect(contextPath = null) { |
|
325 | 376 |
try { |
326 |
- const storageMode = {}; |
|
327 |
- storageMode.strgMode = this.strgMode; |
|
328 |
- await saveByStorageMode(storageMode); |
|
329 |
- alert('스토리지 방식이 변경되었습니다.\n다시 로그인해주세요.'); |
|
377 |
+ console.log('완전한 정리 시작'); |
|
378 |
+ |
|
379 |
+ // 1. 스토어 완전 초기화 |
|
330 | 380 |
this.$store.commit("setStoreReset"); |
331 |
- window.location = this.$filters.ctxPath('/cmslogin.page'); |
|
381 |
+ |
|
382 |
+ // 2. 모든 저장소 정리 |
|
383 |
+ this.clearAllStorages(); |
|
384 |
+ |
|
385 |
+ // 3. 모든 쿠키 제거 (클라이언트 사이드) |
|
386 |
+ this.clearAllClientCookies(); |
|
387 |
+ |
|
388 |
+ // 4. 브라우저 캐시 정리 |
|
389 |
+ this.clearBrowserCache(); |
|
390 |
+ |
|
391 |
+ // 5. 페이지 이동 |
|
392 |
+ const targetPath = contextPath !== null ? |
|
393 |
+ `${contextPath}/cmslogin.page` : |
|
394 |
+ this.$filters.ctxPath('/cmslogin.page'); |
|
395 |
+ |
|
396 |
+ console.log('리다이렉트 경로:', targetPath); |
|
397 |
+ |
|
398 |
+ // 히스토리 정리 후 이동 |
|
399 |
+ window.history.replaceState(null, '', targetPath); |
|
400 |
+ window.location.href = targetPath; |
|
401 |
+ |
|
332 | 402 |
} catch (error) { |
333 |
- const errorData = error.response.data; |
|
334 |
- if (errorData.message != null && errorData.message != "") { |
|
335 |
- alert(error.response.data.message); |
|
336 |
- } else { |
|
337 |
- alert("에러가 발생했습니다.\n관리자에게 문의해주세요."); |
|
338 |
- } |
|
339 |
- this.strgMode = this.previousStrgMode; |
|
403 |
+ console.error('완전한 정리 중 오류:', error); |
|
404 |
+ // 최종 수단: 강제 새로고침 |
|
405 |
+ window.location.reload(); |
|
340 | 406 |
} |
341 | 407 |
}, |
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 |
+ } |
|
342 | 509 |
} |
343 | 510 |
} |
344 | 511 |
</script>(파일 끝에 줄바꿈 문자 없음) |
--- client/views/pages/adm/system/networkAccessControl/NetworkAccessControlInsert.vue
+++ client/views/pages/adm/system/networkAccessControl/NetworkAccessControlInsert.vue
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 |
</div> |
27 | 27 |
<div class="layout"> |
28 | 28 |
<label for="" class="form-title"><span>*</span>제어 경로</label> |
29 |
- <input type="text" class="form-control sm" v-model="accesCtrl.cntrlCrs" placeholder="제어할 경로 URL을 입력하세요."/> |
|
29 |
+ <input type="text" class="form-control sm" v-model="accesCtrl.cntrPath" placeholder="제어할 경로 URL을 입력하세요."/> |
|
30 | 30 |
</div> |
31 | 31 |
</div> |
32 | 32 |
</div> |
... | ... | @@ -170,7 +170,7 @@ |
170 | 170 |
alert('IP 형식이 다릅니다.'); |
171 | 171 |
return false; |
172 | 172 |
} |
173 |
- if (this.accesCtrl.cntrlCrs == null || this.accesCtrl.cntrlCrs == '') { |
|
173 |
+ if (this.accesCtrl.cntrPath == null || this.accesCtrl.cntrPath == '') { |
|
174 | 174 |
alert('제어 경로를 입력하세요.'); |
175 | 175 |
return false; |
176 | 176 |
} |
--- client/views/pages/adm/system/networkAccessControl/NetworkAccessControlSelectList.vue
+++ client/views/pages/adm/system/networkAccessControl/NetworkAccessControlSelectList.vue
... | ... | @@ -141,7 +141,7 @@ |
141 | 141 |
this.listCnt - |
142 | 142 |
idx - |
143 | 143 |
(this.search.currentPage - 1) * this.search.recordSize, // 번호 |
144 |
- cntrlCrs: acces.cntrlCrs, // 경로 |
|
144 |
+ cntrPath: acces.cntrPath, // 경로 |
|
145 | 145 |
cntrlIp: acces.cntrlIp, // 아이피 |
146 | 146 |
cntrlTypeNm: acces.cntrlTypeNm, // 유형 |
147 | 147 |
regDt: acces.regDt, // 등록일 |
--- client/views/pages/adm/system/networkAccessControl/NetworkAccessControlSelectListOne.vue
+++ client/views/pages/adm/system/networkAccessControl/NetworkAccessControlSelectListOne.vue
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 |
</div> |
18 | 18 |
<div class="layout"> |
19 | 19 |
<p class="form-title">제어 경로</p> |
20 |
- <p colspan="3">{{ accesCtrl.cntrlCrs }}</p> |
|
20 |
+ <p colspan="3">{{ accesCtrl.cntrPath }}</p> |
|
21 | 21 |
</div> |
22 | 22 |
</div> |
23 | 23 |
</div> |
--- client/views/pages/login/Login.vue
+++ client/views/pages/login/Login.vue
... | ... | @@ -74,8 +74,7 @@ |
74 | 74 |
|
75 | 75 |
<script> |
76 | 76 |
import { useStore } from "vuex"; |
77 |
-// import store from "../AppStore"; |
|
78 |
-import { loginProc, getUserInfo, oauthLogin } from "../../../resources/api/login"; |
|
77 |
+import { loginProc, getUserInfo } from "../../../resources/api/login"; |
|
79 | 78 |
import { check2ndAuthProc, sendAuthEmailProc } from "../../../resources/api/email"; |
80 | 79 |
import queryParams from "../../../resources/js/queryParams"; |
81 | 80 |
|
... | ... | @@ -86,7 +85,6 @@ |
86 | 85 |
return { |
87 | 86 |
isLoading: false, |
88 | 87 |
member: { lgnId: null, pswd: null, lgnReqPage: 'U' }, |
89 |
- // store: useStore(), |
|
90 | 88 |
isAdminPage: false, |
91 | 89 |
isOAuthLoading: false, |
92 | 90 |
memberInfo: { email: '', code: '' }, |
... | ... | @@ -101,7 +99,9 @@ |
101 | 99 |
|
102 | 100 |
async mounted() { |
103 | 101 |
await this.$nextTick(); |
102 |
+ // OAuth 파라미터가 있으면 콜백 처리 |
|
104 | 103 |
if (this.hasOAuthParams()) { |
104 |
+ console.log('OAuth 파라미터 감지, 콜백 처리 시작'); |
|
105 | 105 |
await this.handleOAuthCallback(); |
106 | 106 |
} |
107 | 107 |
}, |
... | ... | @@ -113,6 +113,7 @@ |
113 | 113 |
watch: { |
114 | 114 |
'$route'(to) { |
115 | 115 |
if (to.query.oauth_success || to.query.error) { |
116 |
+ console.log('라우트 변경으로 OAuth 콜백 감지'); |
|
116 | 117 |
this.handleOAuthCallback(); |
117 | 118 |
} |
118 | 119 |
} |
... | ... | @@ -234,27 +235,41 @@ |
234 | 235 |
|
235 | 236 |
// ========== OAuth2 로그인 ========== |
236 | 237 |
fnOAuthLogin(provider) { |
238 |
+ console.log('OAuth 로그인 시작:', provider); |
|
239 |
+ this.isOAuthLoading = true; |
|
240 |
+ |
|
237 | 241 |
const redirectUrl = this.restoreRedirect("redirect") || this.$route.fullPath; |
238 | 242 |
sessionStorage.setItem('oauth_redirect', redirectUrl); |
239 |
- oauthLogin(provider); |
|
243 |
+ sessionStorage.setItem('oauth_provider', provider); |
|
244 |
+ sessionStorage.setItem('oauth_start_time', Date.now().toString()); |
|
245 |
+ |
|
246 |
+ // OAuth 로그인 페이지로 이동 |
|
247 |
+ window.location.href = `/oauth2/login?provider=${provider}`; |
|
240 | 248 |
}, |
241 | 249 |
|
242 | 250 |
async handleOAuthCallback() { |
243 |
- const { error, errorMessage, oauthSuccess, loginMode } = this.parseOAuthParams(); |
|
251 |
+ const { error, errorMessage, oauthSuccess, lgnMth } = this.parseOAuthParams(); |
|
252 |
+ |
|
253 |
+ console.log('OAuth 콜백 처리:', { error, errorMessage, oauthSuccess, lgnMth }); |
|
244 | 254 |
|
245 | 255 |
if (error) { |
246 | 256 |
this.handleOAuthError(error, errorMessage); |
247 | 257 |
return; |
248 | 258 |
} |
249 | 259 |
|
250 |
- if (oauthSuccess !== 'true' && oauthSuccess !== true) return; |
|
260 |
+ if (oauthSuccess !== 'true' && oauthSuccess !== true) { |
|
261 |
+ console.log('OAuth 성공 파라미터 없음, 처리 건너뜀'); |
|
262 |
+ return; |
|
263 |
+ } |
|
251 | 264 |
|
252 | 265 |
try { |
266 |
+ console.log('OAuth 성공 처리 시작'); |
|
267 |
+ |
|
253 | 268 |
// 기존 시스템 로그인 모드 따라가기 |
254 | 269 |
const finalLoginMode = loginMode || this.$store.state.loginMode || localStorage.getItem('loginMode') || 'J'; |
255 | 270 |
|
271 |
+ console.log('최종 로그인 모드:', finalLoginMode); |
|
256 | 272 |
this.$store.commit("setLoginMode", finalLoginMode); |
257 |
- // localStorage.setItem("loginMode", finalLoginMode); |
|
258 | 273 |
|
259 | 274 |
if (finalLoginMode === 'J') { |
260 | 275 |
await this.handleOAuthJWT(); |
... | ... | @@ -267,6 +282,7 @@ |
267 | 282 |
await this.handleLoginSuccess(); |
268 | 283 |
|
269 | 284 |
} catch (error) { |
285 |
+ console.error('OAuth 처리 중 오류:', error); |
|
270 | 286 |
this.handleOAuthError('processing_error', error.message); |
271 | 287 |
} |
272 | 288 |
}, |
... | ... | @@ -285,11 +301,20 @@ |
285 | 301 |
|
286 | 302 |
async handleOAuthJWT() { |
287 | 303 |
try { |
288 |
- const token = localStorage.getItem('authorization') |
|
304 |
+ console.log('OAuth JWT 모드 처리 시작'); |
|
305 |
+ |
|
306 |
+ // 여러 방법으로 토큰 찾기 |
|
307 |
+ const token = this.getCookie('Authorization') |
|
289 | 308 |
|| this.getCookie('refresh') |
290 |
- || this.getCookie('Authorization'); |
|
309 |
+ || localStorage.getItem('authorization') |
|
310 |
+ || sessionStorage.getItem('authorization'); |
|
291 | 311 |
|
292 |
- const headers = { 'Content-Type': 'application/json' }; |
|
312 |
+ console.log('찾은 토큰:', token ? '있음' : '없음'); |
|
313 |
+ |
|
314 |
+ const headers = { |
|
315 |
+ 'Content-Type': 'application/json', |
|
316 |
+ 'Cache-Control': 'no-cache' |
|
317 |
+ }; |
|
293 | 318 |
|
294 | 319 |
if (token) { |
295 | 320 |
headers['Authorization'] = token.startsWith('Bearer ') ? token : `Bearer ${token}`; |
... | ... | @@ -301,16 +326,24 @@ |
301 | 326 |
credentials: 'include' |
302 | 327 |
}); |
303 | 328 |
|
329 |
+ console.log('OAuth 사용자 정보 응답 상태:', response.status); |
|
330 |
+ |
|
304 | 331 |
if (response.status === 200) { |
305 | 332 |
const result = await response.json(); |
333 |
+ console.log('OAuth 사용자 정보:', result); |
|
306 | 334 |
|
307 | 335 |
if (result.success || result.data) { |
308 | 336 |
const userInfo = result.data; |
337 |
+ |
|
338 |
+ // 토큰이 응답에 있으면 사용, 없으면 기존 토큰 사용 |
|
339 |
+ const finalToken = result.data.token || token; |
|
340 |
+ |
|
309 | 341 |
const roles = Array.isArray(userInfo.roles) ? |
310 | 342 |
userInfo.roles.map(r => ({ authority: r.authrtCd || r.authority })) : |
311 | 343 |
userInfo.roles; |
312 | 344 |
|
313 |
- this.setAuthInfo("J", token, { ...userInfo, roles }); |
|
345 |
+ this.setAuthInfo("J", finalToken, { ...userInfo, roles }); |
|
346 |
+ console.log('JWT 인증 정보 설정 완료'); |
|
314 | 347 |
|
315 | 348 |
} else { |
316 | 349 |
throw new Error('서버에서 실패 응답'); |
... | ... | @@ -320,31 +353,51 @@ |
320 | 353 |
} |
321 | 354 |
|
322 | 355 |
} catch (error) { |
356 |
+ console.error('OAuth JWT 처리 실패:', error); |
|
323 | 357 |
throw error; |
324 | 358 |
} |
325 | 359 |
}, |
326 | 360 |
|
327 | 361 |
async handleOAuthSession() { |
328 | 362 |
try { |
329 |
- const userInfoRes = await getUserInfo(); |
|
363 |
+ console.log('OAuth 세션 모드 처리 시작'); |
|
364 |
+ |
|
365 |
+ const userInfoRes = await fetch('/oauth2/getUserInfo.json', { |
|
366 |
+ method: 'POST', |
|
367 |
+ credentials: 'include', |
|
368 |
+ headers: { |
|
369 |
+ 'Content-Type': 'application/json', |
|
370 |
+ 'Cache-Control': 'no-cache' |
|
371 |
+ } |
|
372 |
+ }); |
|
373 |
+ |
|
374 |
+ console.log('세션 사용자 정보 응답 상태:', userInfoRes.status); |
|
375 |
+ |
|
330 | 376 |
if (!userInfoRes || userInfoRes.status !== 200) { |
331 | 377 |
throw new Error('세션 정보를 가져올 수 없습니다.'); |
332 | 378 |
} |
333 | 379 |
|
334 |
- const userInfo = userInfoRes.data.data; |
|
380 |
+ const result = await userInfoRes.json(); |
|
381 |
+ console.log('세션 사용자 정보:', result); |
|
382 |
+ |
|
383 |
+ const userInfo = result.data; |
|
335 | 384 |
const roles = Array.isArray(userInfo.roles) ? |
336 | 385 |
userInfo.roles.map(r => ({ authority: r.authrtCd || r.authority })) : |
337 | 386 |
userInfo.roles; |
338 | 387 |
|
339 | 388 |
this.setAuthInfo('S', null, { ...userInfo, roles }); |
389 |
+ console.log('세션 인증 정보 설정 완료'); |
|
340 | 390 |
|
341 | 391 |
} catch (error) { |
392 |
+ console.error('OAuth 세션 처리 실패:', error); |
|
342 | 393 |
throw error; |
343 | 394 |
} |
344 | 395 |
}, |
345 | 396 |
|
346 | 397 |
// ========== 공통 처리 ========== |
347 | 398 |
setAuthInfo(loginMode, token, userInfo) { |
399 |
+ console.log('인증 정보 설정:', { loginMode, userInfo: userInfo.mbrId }); |
|
400 |
+ |
|
348 | 401 |
// Store 설정 |
349 | 402 |
try { |
350 | 403 |
if (typeof this.$store !== 'undefined' && this.$store.commit) { |
... | ... | @@ -353,27 +406,20 @@ |
353 | 406 |
this.$store.commit("setMbrId", userInfo.mbrId); |
354 | 407 |
this.$store.commit("setMbrNm", userInfo.mbrNm); |
355 | 408 |
this.$store.commit("setRoles", userInfo.roles); |
409 |
+ console.log('Vuex 스토어 설정 완료'); |
|
356 | 410 |
} |
357 | 411 |
} catch (e) { |
358 |
- console.warn("store 설정 실패, localStorage만 사용:", e); |
|
412 |
+ console.warn("store 설정 실패:", e); |
|
359 | 413 |
} |
360 |
- |
|
361 |
- // localStorage 저장 |
|
362 |
- // localStorage.setItem("loginMode", loginMode); |
|
363 |
- // localStorage.setItem("mbrId", userInfo.mbrId); |
|
364 |
- // localStorage.setItem("mbrNm", userInfo.mbrNm); |
|
365 |
- // localStorage.setItem("roles", JSON.stringify(userInfo.roles)); |
|
366 |
- |
|
367 |
- // if (token && loginMode === 'J') { |
|
368 |
- // localStorage.setItem("authorization", token); |
|
369 |
- // } else { |
|
370 |
- // localStorage.removeItem("authorization"); |
|
371 |
- // } |
|
372 | 414 |
}, |
373 | 415 |
|
374 | 416 |
async handleLoginSuccess() { |
417 |
+ console.log('로그인 성공 후 처리 시작'); |
|
418 |
+ |
|
375 | 419 |
const isAdmin = this.$store.state.roles.some(role => role.authority === "ROLE_ADMIN"); |
376 | 420 |
let redirectUrl = this.restoreRedirect("redirect") || sessionStorage.getItem('oauth_redirect'); |
421 |
+ |
|
422 |
+ console.log('관리자 여부:', isAdmin, '리다이렉트 URL:', redirectUrl); |
|
377 | 423 |
|
378 | 424 |
if (redirectUrl && this.shouldRedirectToMain(redirectUrl)) { |
379 | 425 |
redirectUrl = this.$filters.ctxPath("/"); |
... | ... | @@ -385,6 +431,8 @@ |
385 | 431 |
|
386 | 432 |
const targetPath = this.getValidRedirectPath(redirectUrl, isAdmin); |
387 | 433 |
|
434 |
+ console.log('최종 이동 경로:', targetPath); |
|
435 |
+ |
|
388 | 436 |
await this.$nextTick(); |
389 | 437 |
this.$router.push({ path: targetPath }); |
390 | 438 |
|
... | ... | @@ -395,11 +443,12 @@ |
395 | 443 |
shouldRedirectToMain(url) { |
396 | 444 |
return url.includes("/searchId.page") || |
397 | 445 |
url.includes("/resetPswd.page") || |
398 |
- url.includes("/login.page"); |
|
446 |
+ url.includes("/login.page") || |
|
447 |
+ url.includes("/cmslogin.page"); |
|
399 | 448 |
}, |
400 | 449 |
|
401 | 450 |
getValidRedirectPath(redirectUrl, isAdmin) { |
402 |
- if (redirectUrl && !redirectUrl.includes("login.page")) { |
|
451 |
+ if (redirectUrl && !redirectUrl.includes("login.page") && !redirectUrl.includes("cmslogin.page")) { |
|
403 | 452 |
const routeExists = this.$router.getRoutes().some(route => route.path === redirectUrl); |
404 | 453 |
if (routeExists) return redirectUrl; |
405 | 454 |
} |
... | ... | @@ -411,21 +460,29 @@ |
411 | 460 |
|
412 | 461 |
// ========== 에러 처리 및 정리 ========== |
413 | 462 |
handleOAuthError(error, errorMessage) { |
463 |
+ console.error('OAuth 에러 처리:', { error, errorMessage }); |
|
464 |
+ |
|
414 | 465 |
this.isOAuthLoading = false; |
415 | 466 |
this.cleanupOAuth(); |
416 | 467 |
|
417 | 468 |
const message = decodeURIComponent(errorMessage || error || 'OAuth 로그인에 실패했습니다.'); |
418 | 469 |
alert(`소셜 로그인 실패: ${message}`); |
419 | 470 |
|
420 |
- this.$router.push({ path: this.$filters.ctxPath("/login.page") }); |
|
471 |
+ // 현재 페이지가 메인 페이지가 아니면 로그인 페이지로 이동 |
|
472 |
+ if (this.$route.path !== this.$filters.ctxPath("/")) { |
|
473 |
+ this.$router.push({ path: this.$filters.ctxPath("/login.page") }); |
|
474 |
+ } |
|
421 | 475 |
}, |
422 | 476 |
|
423 | 477 |
cleanupOAuth() { |
478 |
+ console.log('OAuth 정리 작업'); |
|
479 |
+ |
|
424 | 480 |
sessionStorage.removeItem('oauth_redirect'); |
425 | 481 |
sessionStorage.removeItem('oauth_provider'); |
426 | 482 |
sessionStorage.removeItem('oauth_start_time'); |
427 | 483 |
this.isOAuthLoading = false; |
428 | 484 |
|
485 |
+ // URL에서 OAuth 파라미터 제거 |
|
429 | 486 |
const cleanUrl = window.location.pathname; |
430 | 487 |
window.history.replaceState({}, document.title, cleanUrl); |
431 | 488 |
}, |
... | ... | @@ -434,7 +491,12 @@ |
434 | 491 |
getCookie(name) { |
435 | 492 |
const value = `; ${document.cookie}`; |
436 | 493 |
const parts = value.split(`; ${name}=`); |
437 |
- return parts.length === 2 ? parts.pop().split(';').shift() : null; |
|
494 |
+ if (parts.length === 2) { |
|
495 |
+ const cookieValue = parts.pop().split(';').shift(); |
|
496 |
+ console.log(`쿠키 ${name}:`, cookieValue ? '있음' : '없음'); |
|
497 |
+ return cookieValue; |
|
498 |
+ } |
|
499 |
+ return null; |
|
438 | 500 |
}, |
439 | 501 |
|
440 | 502 |
moveSearchId() { |
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?