import { createWebHistory, createRouter } from "vue-router"; import { getGlobalStore } from "./AppStore"; import filters from '../common/filters'; // 메인화면 import Main from "./user/portal/main/Main.vue"; // 관리자 import CommonSelectList from "./adm/boardManagement/template/commonTemplate/CommonSelectList.vue"; import CommonSelectListOne from "./adm/boardManagement/template/commonTemplate/CommonSelectListOne.vue"; // NotFound import NotFound from "./user/etc/NotFound.vue"; const beforeRoutes = [ /* 메인화면 */ { path: "/", name: "main", korName: "홈", component: Main }, { path: '/:pathMatch(.*)*', name: "PageNotFound", component: NotFound }, // 관리자 { path: "/adm", children: [ { path: "commonSelectListOne.page", name: "CommonSelectListOne", korName: "", component: CommonSelectListOne }, { path: "commonSelectList.page", name: "CommonSelectList", korName: "", component: CommonSelectList }, ], }, ]; import { findAll, accessCheck } from "../../resources/api/router"; import { getCntxtPth } from "../../resources/api/cntxtPth"; import { save } from "../../resources/api/cntnStats"; // Context Path 정보 호출 async function getContextPath() { try { const store = getGlobalStore(); // 전역 스토어 가져오기 const res = await getCntxtPth(); if (res.status == 200) { let ctx = res.data.data || ''; // Context Path 정보 if(ctx == '/') { ctx = ''; // Context Path가 '/'인 경우 빈 문자열로 설정 } store.commit("setContextPath", ctx); // Context Path 정보 저장 return ctx; }else { store.commit("setStoreReset"); window.location = filters.ctxPath('/') } } catch (error) { return []; } } // 라우터 정보 호출 async function fetchRoutes() { try { const store = getGlobalStore(); // 전역 스토어 가져오기 const res = await findAll(); if (res.status == 200) { const newRoutes = res.data.data.map(route => ({ path: route.userPagePath, name: route.contsEngNm, korName: route.contsKornNm, component: () => import(`${route.compnPath}`), meta: { authrt: route.authrtList, typeId: route.contsId, korName: route.contsKornNm } })); return newRoutes; }else { store.commit("setStoreReset"); window.location = filters.ctxPath('/') } } catch (error) { return []; } } // Context Path를 라우터에 추가하는 함수 function addContextPathToRoutes(routes, contextPath) { return routes.map(route => { const newRoute = { ...route, path: contextPath + route.path }; // if (route.children && route.children.length > 0) { // newRoute.children = addContextPathToRoutes(route.children, contextPath); // } return newRoute; }); } // 접근 제어 확인 async function accessUrl(path) { try { const res = await accessCheck({ path: path }); if (res.status == 200) { return res.data.data; } } catch (error) { return false; } } // 사용자 권한과 라우터에 포함되어 있는 권한을 비교하여 최종 권한 추출 function mergeAuth(userRoles, routeMeta) { const result = { inqAuthrt: 'N', // 읽기 권한 regAuthrt: 'N', // 쓰기 권한 mdfcnAuthrt: 'N', // 수정 권한 delAuthrt: 'N', // 삭제 권한 fileDwnldAuthrt: 'N', // 파일 다운로드 권한 }; if (!routeMeta || !routeMeta.authrt || routeMeta.authrt.length === 0) { return result; } routeMeta.authrt.forEach(auth => { if (userRoles.includes(auth.authrtCd)) { if (auth.inqAuthrt === 'Y') result.inqAuthrt = 'Y'; if (auth.regAuthrt === 'Y') result.regAuthrt = 'Y'; if (auth.mdfcnAuthrt === 'Y') result.mdfcnAuthrt = 'Y'; if (auth.delAuthrt === 'Y') result.delAuthrt = 'Y'; if (auth.fileDwnldAuthrt === 'Y') result.fileDwnldAuthrt = 'Y'; } }); return result; } // 통계 등록 async function cntnStatsSave(typeId, roles) { try { const cntnStats = { 'typeId': typeId, 'mbrAuthList': roles } await save(cntnStats); } catch (error) { } } // 권한 검증 function isValidRole() { const store = getGlobalStore(); // 전역 스토어 가져오기 const roles = store.state.roles; if (!Array.isArray(roles)) { store.commit("setStoreReset"); return false; } for (const role of roles) { if (typeof role !== 'object' || !role.hasOwnProperty('authority')) { store.commit("setStoreReset"); return false; } } return true; } export default async function createAppRouter() { const ctx = await getContextPath(); // DB에 적재된 Context Path 정보 호출 const dynamicRoutes = await fetchRoutes(); // DB에 적재된 라우터 정보 호출 const prefixedBeforeRoutes = addContextPathToRoutes(beforeRoutes, ctx); // 기존 라우터 정보에 Context Path 추가 const prefixedDynamicRoutes = addContextPathToRoutes(dynamicRoutes, ctx); // DB에 적재된 라우터 정보에 Context Path 추가 console.log('prefixedDynamicRoutes: ', prefixedDynamicRoutes); const newRoutes = prefixedBeforeRoutes.concat(prefixedDynamicRoutes); // 기존 라우터 정보와 합치기 console.log('newRoutes: ', newRoutes); const AppRouter = createRouter({ history: createWebHistory(), routes: newRoutes, }); AppRouter.beforeEach(async (to, from, next) => { const store = getGlobalStore(); // 전역 스토어 가져오기 const contextPath = store.state.contextPath; // Context Path 정보 const admPath = to.path.includes('/adm'); // 관리자 페이지 여부 (true: 관리자 페이지, false: 사용자 페이지) if(to.name === 'PageNotFound') { next(); return; } // 로그인 모드 확인 let loginMode = store.state.loginMode; // 로그인 모드가 여전히 없으면 localStorage에서 다시 한번 확인 if (!loginMode || loginMode === 'undefined') { // 스토어에 없으면 localStorage 확인 loginMode = localStorage.getItem('loginMode') || sessionStorage.getItem('loginMode'); } if (!loginMode || loginMode === 'undefined') { // 여전히 없으면 기본값 설정 loginMode = 'J'; } if (store.state.loginMode !== loginMode) { store.commit('setLoginMode', loginMode); } // 로그인 상태 확인 개선 let isLogin = false; if (loginMode === 'J') { // JWT 모드: authorization 토큰 확인 const token = store.state.authorization || localStorage.getItem('authorization'); isLogin = !!token; } else if (loginMode === 'S') { // 세션 모드: mbrId 또는 mbrNm 확인 const mbrId = store.state.mbrId || localStorage.getItem('mbrId') || sessionStorage.getItem('mbrId'); const mbrNm = store.state.mbrNm || localStorage.getItem('mbrNm') || sessionStorage.getItem('mbrNm'); isLogin = !!(mbrId || mbrNm); } // OAuth2 콜백 처리 - 로그인 페이지에서만 처리 if (to.path.includes('/login.page') && (to.query.oauth_success || to.query.error)) { next(); return; } // 접근 제어 확인 const accesCheck = await accessUrl(to.path); const roleCheck = isValidRole(); if (!accesCheck || !roleCheck) { alert('접근이 불가합니다.\n관리자에게 문의하세요.'); next(filters.ctxPath('/')); return; } // 경로에 따른 사용자 타입 설정 if (to.path === filters.ctxPath('/')) { store.commit('setUserType', 'portal') } else if (to.path.startsWith(filters.ctxPath('/adm'))) { store.commit('setUserType', 'adm'); } if (to.path === filters.ctxPath('/login.page')) { store.commit('setPath', to.path); next(); return; } const mbrAuth = store.state.roles.map(auth => auth.authority); // 사용자 권한 정보 const pageAuth = mergeAuth(mbrAuth, to.meta); sessionStorage.setItem("redirect", to.fullPath); // 메인 페이지 or 로그인 페이지 if (to.path === filters.ctxPath('/') || to.path.includes('/login.page') || to.path.includes('/cmslogin.page') || to.path.startsWith(filters.ctxPath('/cmmn/')) || to.path.includes('/signUp.page') || to.path.includes('/searchId.page') || to.path.includes('/resetPswd.page')) { let path = to.path; // 게시판일 경우 .page로 끝나는 경로가 있으므로 마지막 '/' 이전 경로로 설정 if (to.path.includes('BBS_MNG')) { let logicalPath = to.path; // context path 제거 if (contextPath !== '/' && logicalPath.startsWith(contextPath)) { logicalPath = logicalPath.substring(contextPath.length); } const lastSlashIndex = logicalPath.lastIndexOf('/'); // 마지막 '/' 인덱스 path = logicalPath.substring(0, lastSlashIndex); // 마지막 '/' 이전 경로 } store.commit('setPath', path); store.commit('setPageAuth', pageAuth); if (to.path === filters.ctxPath('/') || path.includes('/main.page')) { await cntnStatsSave(null, mbrAuth); // 메인 페이지 접속 시 사용자 접속 통계 증가 } next(); } else if (isLogin) { // 로그인 상태이고, 권한이 허용인 경우 검사 const hasAcc = to.matched.some(record => { if (!record.meta.authrt) return false; return record.meta.authrt.some(auth => { // 경로별 권한 검사 if (to.path.includes('/list.page')) { // 목록 권한 검증 return mbrAuth.includes(auth.authrtCd) && auth.inqAuthrt === 'Y'; } else if (to.path.includes('/insert.page')) { // 등록 및 수정 권한 검증 return mbrAuth.includes(auth.authrtCd) && auth.regAuthrt === 'Y'; } else if (to.path.includes('/view.page')) { // 상세조회 권한 검증 return mbrAuth.includes(auth.authrtCd) && auth.inqAuthrt === 'Y'; } else if (to.path.includes('/main.page')) { // 메인 페이지 권한 검증 return mbrAuth.includes(auth.authrtCd) && auth.inqAuthrt === 'Y'; } else if (to.path.includes('/search.page')) { return mbrAuth.includes(auth.authrtCd) && auth.inqAuthrt === 'Y'; } else { return false; } }); }); // 권한이 있고 접근 가능한 경우 if (hasAcc) { if (to.path.includes('.page')) { let logicalPath = to.path; // context path 제거 if (contextPath !== '/' && logicalPath.startsWith(contextPath)) { logicalPath = logicalPath.substring(contextPath.length); } const lastSlashIndex = logicalPath.lastIndexOf('/'); // 마지막 '/' 인덱스 const path = logicalPath.substring(0, lastSlashIndex); // 마지막 '/' 이전 경로 store.commit('setPath', path); } // 접속 통계 if (to.path.includes('/main.page')) { await cntnStatsSave(null, mbrAuth); // 메인 페이지 접속 시 사용자 접속 통계 증가 } else { if (!to.meta.typeId.includes('BBS_MNG') || to.path.includes('/list.page')) { await cntnStatsSave(to.meta.typeId, mbrAuth); } } store.commit('setPageAuth', pageAuth); next(); // 권한이 없는 경우 이전 페이지 or / 이동 } else { alert('접근 권한이 없습니다.'); window.history.back(); } } else { // 관리자 로그인이 필요한 경우 if(admPath) { sessionStorage.setItem("redirect", to.fullPath); next({ path: filters.ctxPath("/cmslogin.page") }); } else { // 일반 사용자 페이지에서 로그인이 필요한 경우 sessionStorage.setItem("redirect", to.fullPath); next({ path: filters.ctxPath("/login.page") }); } } }); return AppRouter; }