
File name
Commit message
Commit date
05-22
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
File name
Commit message
Commit date
<template>
<div class="content-zone full-page">
<div class="content">
<div class="scroll">
<div open class="form-box">
<div class="form-box-title">
<p>기본정보</p>
<p><span>*</span>시스템 정책을 변경하면 전체 사용자가 로그아웃됩니다.</p>
</div>
<div class="form-content">
<div class="layout">
<label class="form-title">중복로그인 설정</label>
<div class="form-group">
<div class="check-area">
<div class="form-check">
<input type="radio" id="allowMultipleLoginY" class="mr5" value="Y" v-model="allowMultipleLogin"
@change="saveByLoginPolicy" />
<label for="allowMultipleLoginY">허용</label>
</div>
<div class="form-check">
<input type="radio" id="allowMultipleLoginN" class="mr5" value="N" v-model="allowMultipleLogin"
@change="saveByLoginPolicy" />
<label for="allowMultipleLoginN">비허용</label>
</div>
</div>
</div>
</div>
<div class="layout border-bottom">
<label class="form-title">로그인 방식 설정</label>
<div class="form-group">
<div class="check-area">
<div class="form-check">
<input type="radio" id="loginModeJ" class="mr5" value="J" v-model="lgnMode"
@change="saveByLoginMode" />
<label for="loginModeJ">JWT 방식</label>
</div>
<div class="form-check">
<input type="radio" id="loginModeS" class="mr5" value="S" v-model="lgnMode"
@change="saveByLoginMode" />
<label for="loginModeS">SESSION 방식</label>
</div>
</div>
</div>
</div>
<div class="layout">
<label class="form-title">스토리지 방식 설정</label>
<div class="form-group">
<div class="check-area">
<div class="form-check">
<input type="radio" id="storageModeL" class="mr5" value="L" v-model="strgMode"
@change="saveByStorageMode" />
<label for="storageModeL">LOCAL 방식</label>
</div>
<div class="form-check">
<input type="radio" id="storageModeS" class="mr5" value="S" v-model="strgMode"
@change="saveByStorageMode" />
<label for="storageModeS">SESSION 방식</label>
</div>
</div>
</div>
</div>
<div class="layout">
<label class="form-title">이메일 2차 인증 설정</label>
<div class="form-group">
<div class="check-area">
<div class="form-check">
<input type="radio" id="use2ndAuthY" class="mr5" value="Y" v-model="use2ndAuth"
@change="saveBy2ndAuth" />
<label for="use2ndAuthY">사용</label>
</div>
<div class="form-check">
<input type="radio" id="use2ndAuthN" class="mr5" value="N" v-model="use2ndAuth"
@change="saveBy2ndAuth" />
<label for="use2ndAuthN">미사용</label>
</div>
</div>
</div>
</div>
<div class="layout">
<label class="form-title">Context Path 설정</label>
<div class="form-group">
<div class="check-area">
<div class="form-check">
<input type="text" id="cntxtPth" class="form-control sm" v-model="cntxtPth" ref="cntxtPth" />
</div>
<button class="btn sm main" @click="saveByContextPath">저장</button>
</div>
<span class="ml10 gray">
<strong>/</strong> 또는 <strong>/경로</strong> 형식으로 입력하세요.
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import {
findAllByLoginPolicy,
saveByLoginPolicy,
findAllByLoginMode,
saveByLoginMode,
findAllBy2ndAuth,
saveBy2ndAuth,
findAllByStorageMode,
saveByStorageMode
} from '../../../../../resources/api/loginPolicy.js';
import { getCntxtPth, saveCntxtPth } from '../../../../../resources/api/cntxtPth';
import { cacheReSet } from "../../../../../resources/api/cacheReSet";
export default {
data() {
return {
allowMultipleLogin: null,
lgnMode: null,
previousLgnMode: null, // 이전 로그인 모드 저장
previousAllowMultipleLogin: null,
cntxtPth: '/', // context path 초기값
defaultCntxtPth: null, // 현재 설정된 Context Path
use2ndAuth: null, // 2차 인증 사용 여부
previousUse2ndAuth: null, // 이전 2차 인증 사용 여부 저장
strgMode: null, // 스토리지 방식
previousStrgMode: null, // 이전 스토리지 방식 저장
}
},
created() {
this.findAll();
this.findCntxtPth();
},
mounted() {
},
methods: {
async findAll() {
try {
const res1 = await findAllByLoginPolicy();
this.allowMultipleLogin = res1.data.data === true ? 'Y' : 'N';
this.previousAllowMultipleLogin = this.allowMultipleLogin;
const res2 = await findAllByLoginMode();
this.lgnMode = res2.data.data;
this.previousLgnMode = this.lgnMode; // 초기 상태를 저장
const res3 = await findAllBy2ndAuth();
this.use2ndAuth = res3.data.data === true ? 'Y' : 'N';
this.previousUse2ndAuth = this.use2ndAuth; // 초기 상태를 저장
const res4 = await findAllByStorageMode();
this.strgMode = res4.data.data;
this.previousStrgMode = this.strgMode; // 초기 상태를 저장
} catch (err) {
alert('설정 정보를 불러오는 데 실패했습니다.');
}
},
// 중복로그인 설정 저장 - 개선된 버전
async saveByLoginPolicy() {
const confirmed = confirm(
'로그인 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
);
if (!confirmed) {
this.allowMultipleLogin = this.previousAllowMultipleLogin;
return;
}
try {
const loginPolicy = {};
loginPolicy.mltLgnPrmYn = this.allowMultipleLogin;
await saveByLoginPolicy(loginPolicy);
// 전체 사용자 로그아웃 API 호출
await this.performGlobalLogout();
alert('중복 로그인 설정이 저장되었습니다.');
// 완전한 정리 후 로그인 페이지로 이동
await this.performCompleteCleanupAndRedirect();
} catch (err) {
alert('중복 로그인 설정 저장 실패: ' + (err.response?.data?.message || err.message));
this.allowMultipleLogin = this.previousAllowMultipleLogin;
}
},
// 로그인 방식 저장 - 개선된 버전
async saveByLoginMode() {
const confirmed = confirm(
'로그인 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
);
if (!confirmed) {
this.lgnMode = this.previousLgnMode;
return;
}
try {
const loginMode = {};
loginMode.lgnMode = this.lgnMode;
await saveByLoginMode(loginMode);
// 전체 사용자 로그아웃 API 호출
await this.performGlobalLogout();
alert('로그인 방식이 변경되었습니다.\n다시 로그인해주세요.');
// 완전한 정리 후 로그인 페이지로 이동
await this.performCompleteCleanupAndRedirect();
} catch (err) {
alert('로그인 방식 저장 실패: ' + (err.response?.data?.message || err.message));
this.lgnMode = this.previousLgnMode;
}
},
// 스토리지 방식 저장 - 개선된 버전
async saveByStorageMode() {
const confirmed = confirm(
'스토리지 방식을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
);
if (!confirmed) {
this.strgMode = this.previousStrgMode;
return;
}
try {
const storageMode = {};
storageMode.strgMth = this.strgMode;
await saveByStorageMode(storageMode);
alert('스토리지 방식이 변경되었습니다.\n다시 로그인해주세요.');
this.$store.commit("setStoreReset");
window.location = this.$filters.ctxPath('/cmslogin.page');
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
this.strgMode = this.previousStrgMode;
}
},
// Context Path 저장
async saveByContextPath() {
if (!this.validation()) {
return;
}
const isCheck = confirm("Context Path를 변경하면 로그아웃됩니다.\n계속하시겠습니까?");
// const isCheck = confirm("Context Path를 변경하시겠습니까?");
if (isCheck) {
try {
let ctx = { path: this.cntxtPth };
const res = await saveCntxtPth(ctx);
alert(res.data.message);
if (res.status == 200) {
let storeCtx = this.cntxtPth;
if (storeCtx == '/') {
storeCtx = '';
}
this.$store.commit("setContextPath", storeCtx); // 캐시 초기화 요청을 보내기 위한 Context Path 정보 저장
await this.$store.dispatch("logout");
/* const cacheRes = await cacheReSet(); // 캐시 초기화
if (cacheRes.status !== 200) {
alert(cacheRes.data.message);
}
this.$store.commit("setStoreReset"); // 캐시 초기화 후 Store 초기화
this.$store.commit("setContextPath", storeCtx); // 라우터 Context Path 정보 저장
window.location.href = `${storeCtx}/login.page`;
// window.location.href = `${storeCtx}/adm/main.page`; */
} else {
alert(res.data.message);
}
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
}
},
// 2차 인증 설정 저장
async saveBy2ndAuth() {
const confirmed = confirm(
'2차 인증 설정을 변경하면 전체 사용자가 로그아웃됩니다.\n계속하시겠습니까?'
);
if (!confirmed) {
this.use2ndAuth = this.previousUse2ndAuth;
return;
}
try {
const email2ndAuth = {};
email2ndAuth.useYn = this.use2ndAuth;
await saveBy2ndAuth(email2ndAuth);
alert('이메일 2차 인증 설정이 저장되었습니다.');
// this.$store.commit("setStoreReset");
// window.location = this.$filters.ctxPath('/cmslogin.page');
} catch (error) {
const errorData = error.response.data;
if (errorData.message != null && errorData.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
},
// 최신 Context Path 조회
async findCntxtPth() {
try {
const res = await getCntxtPth();
if (res.status == 200) {
this.cntxtPth = res.data.data;
this.defaultCntxtPth = res.data.data;
}
} catch (error) {
const errorData = error.response?.data;
if (errorData?.message != null && errorData?.message != "") {
alert(error.response.data.message);
} else {
alert("에러가 발생했습니다.\n관리자에게 문의해주세요.");
}
}
},
// 유효성 검사
validation() {
const regex = /^\/[a-zA-Z0-9\-_]*$/;
if (this.cntxtPth == null || this.cntxtPth == "") {
alert("Context Path를 입력해주세요.");
this.$refs.cntxtPth.focus();
return false;
}
if (this.cntxtPth.length > 50) {
alert("Context Path는 50자 이내로 입력해주세요.");
this.$refs.cntxtPth.focus();
return false;
}
if (this.cntxtPth == this.defaultCntxtPth) {
alert("변경된 내용이 없습니다.");
this.$refs.cntxtPth.focus();
return false;
}
if (!regex.test(this.cntxtPth)) {
alert("Context Path는 '/'로 시작해야 하며, 알파벳, 숫자, '-' 또는 '_'만 포함할 수 있습니다.");
this.$refs.cntxtPth.focus();
return false;
}
return true;
},
// 전체 사용자 로그아웃 API 호출
async performGlobalLogout() {
try {
console.log('전체 사용자 로그아웃 API 호출 시작');
await fetch('/mbr/logoutAll.json', {
method: 'POST',
credentials: 'include',
headers: {
'Content-Type': 'application/json'
}
});
console.log('전체 사용자 로그아웃 API 호출 완료');
} catch (error) {
console.warn('전체 로그아웃 API 호출 실패:', error);
// 실패해도 계속 진행
}
},
// 완전한 정리 및 리다이렉트
async performCompleteCleanupAndRedirect(contextPath = null) {
try {
console.log('완전한 정리 시작');
// 1. 스토어 완전 초기화
this.$store.commit("setStoreReset");
// 2. 모든 저장소 정리
this.clearAllStorages();
// 3. 모든 쿠키 제거 (클라이언트 사이드)
this.clearAllClientCookies();
// 4. 브라우저 캐시 정리
this.clearBrowserCache();
// 5. 페이지 이동
const targetPath = contextPath !== null ?
`${contextPath}/cmslogin.page` :
this.$filters.ctxPath('/cmslogin.page');
console.log('리다이렉트 경로:', targetPath);
// 히스토리 정리 후 이동
window.history.replaceState(null, '', targetPath);
window.location.href = targetPath;
} catch (error) {
console.error('완전한 정리 중 오류:', error);
// 최종 수단: 강제 새로고침
window.location.reload();
}
},
// 모든 저장소 정리
clearAllStorages() {
try {
console.log('저장소 정리 시작');
// localStorage 완전 정리
const localStorageKeys = Object.keys(localStorage);
localStorageKeys.forEach(key => {
localStorage.removeItem(key);
});
localStorage.clear();
// sessionStorage 완전 정리
const sessionStorageKeys = Object.keys(sessionStorage);
sessionStorageKeys.forEach(key => {
sessionStorage.removeItem(key);
});
sessionStorage.clear();
console.log('저장소 정리 완료');
} catch (error) {
console.error('저장소 정리 실패:', error);
}
},
// 모든 클라이언트 쿠키 제거
clearAllClientCookies() {
try {
console.log('클라이언트 쿠키 제거 시작');
const cookiesToDelete = [
// 일반 인증 쿠키
'refresh', 'Authorization', 'access_token', 'JSESSIONID', 'SESSION',
// OAuth 관련 쿠키
'oauth_access_token', 'oauth_refresh_token', 'oauth_state',
'OAUTH2_AUTHORIZATION_REQUEST', 'oauth2_auth_request',
// 소셜 로그인 쿠키들
'kakao_login', '_kadu', '_kadub', '_kalt', '_kawlt', '_kawltea', '_karmt', '_karmts',
'NID_AUT', 'NID_SES', 'NID_JKL', 'NID_INF', 'NID_LOG',
'SACSID', 'APISID', 'SSID', 'HSID', 'SID', '1P_JAR',
'__Secure-1PAPISID', '__Secure-1PSID', '__Secure-3PAPISID', '__Secure-3PSID',
// 기타
'remember-me', 'user-session', 'auth-token', 'login-token', 'csrf-token'
];
const domains = ['', '.' + window.location.hostname, window.location.hostname, '.localhost', 'localhost'];
const paths = ['/', '/oauth2', '/login', '/auth', '/api', '/mbr', '/admin'];
cookiesToDelete.forEach(cookieName => {
paths.forEach(path => {
domains.forEach(domain => {
// 기본 쿠키 삭제
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path};`;
// 도메인별 쿠키 삭제
if (domain) {
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=${path}; domain=${domain};`;
}
});
});
});
console.log('클라이언트 쿠키 제거 완료');
} catch (error) {
console.error('클라이언트 쿠키 제거 실패:', error);
}
},
// 브라우저 캐시 정리
clearBrowserCache() {
try {
console.log('브라우저 캐시 정리 시작');
// 캐시 API 지원 확인 및 정리
if ('caches' in window) {
caches.keys().then(cacheNames => {
cacheNames.forEach(cacheName => {
caches.delete(cacheName);
});
}).catch(() => {});
}
// IndexedDB 정리 (가능한 경우)
if ('indexedDB' in window) {
const commonDBNames = ['auth_db', 'user_db', 'session_db'];
commonDBNames.forEach(dbName => {
try {
indexedDB.deleteDatabase(dbName);
} catch (e) {}
});
}
console.log('브라우저 캐시 정리 완료');
} catch (error) {
console.error('브라우저 캐시 정리 실패:', error);
}
}
}
}
</script>