[미들웨어 및 권한 시스템 개선] 기존 auth 미들웨어를 auth.global.ts로 통합하여 로그인 및 권한 체크 로직을 개선하고, 페이지 권한 확인 방식을 동적 라우팅 패턴으로 확장함. 불필요한 코드 제거 및 로그아웃 처리 로직 간소화.
This commit is contained in:
@@ -23,11 +23,9 @@ import AppHeader from "../components/layout/AppHeader.vue";
|
|||||||
import SubMenuBar from "../components/layout/SubMenuBar.vue";
|
import SubMenuBar from "../components/layout/SubMenuBar.vue";
|
||||||
import TabBar from "../components/layout/TabBar.vue";
|
import TabBar from "../components/layout/TabBar.vue";
|
||||||
import { ref, computed } from "vue";
|
import { ref, computed } from "vue";
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
import { useTabsStore } from "../stores/tab";
|
import { useTabsStore } from "../stores/tab";
|
||||||
import { usePermissionsStore } from "~/stores/permissions";
|
import { usePermissionsStore } from "~/stores/permissions";
|
||||||
|
|
||||||
const router = useRouter();
|
|
||||||
const activeMenu = ref("HOME");
|
const activeMenu = ref("HOME");
|
||||||
const showSubmenuBar = ref(false);
|
const showSubmenuBar = ref(false);
|
||||||
|
|
||||||
|
|||||||
32
middleware/auth.global.ts
Normal file
32
middleware/auth.global.ts
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
export default defineNuxtRouteMiddleware(async (to, _from) => {
|
||||||
|
if (import.meta.client) {
|
||||||
|
const userStore = useUserStore();
|
||||||
|
const { hasPagePermission } = usePermission();
|
||||||
|
|
||||||
|
// 공개 라우트 목록 (로그인 없이 접근 가능)
|
||||||
|
const publicRoutes = ["/login", "/register"];
|
||||||
|
|
||||||
|
// 공개 라우트인지 확인
|
||||||
|
const isPublicRoute = publicRoutes.some(route => to.path === route);
|
||||||
|
|
||||||
|
// 공개 라우트가 아닌 경우 로그인 체크
|
||||||
|
if (!isPublicRoute && !userStore.isLoggedIn) {
|
||||||
|
return navigateTo("/login");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 로그인된 사용자의 경우 권한 체크
|
||||||
|
if (userStore.isLoggedIn) {
|
||||||
|
// 루트 경로는 항상 허용
|
||||||
|
if (to.path === "/") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 페이지 권한 체크
|
||||||
|
if (!hasPagePermission(to.path)) {
|
||||||
|
console.log(`페이지 권한이 없습니다.: ${to.path}`);
|
||||||
|
alert(`페이지 권한이 없습니다.`);
|
||||||
|
return navigateTo("/");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
export default defineNuxtRouteMiddleware((to, _from) => {
|
|
||||||
// 클라이언트 사이드에서만 실행
|
|
||||||
if (import.meta.client) {
|
|
||||||
const userStore = useUserStore();
|
|
||||||
const permissionsStore = usePermissionsStore();
|
|
||||||
|
|
||||||
// 보호된 라우트 목록(메뉴 확정되면 수정)
|
|
||||||
const protectedRoutes = ["/admin", "/profile", "/dashboard"];
|
|
||||||
|
|
||||||
// 현재 라우트가 보호된 라우트인지 확인
|
|
||||||
const isProtectedRoute = protectedRoutes.some(route =>
|
|
||||||
to.path.startsWith(route)
|
|
||||||
);
|
|
||||||
|
|
||||||
// 로그인 체크
|
|
||||||
if (isProtectedRoute && !userStore.isLoggedIn) {
|
|
||||||
// 인증되지 않은 사용자를 로그인 페이지로 리다이렉트
|
|
||||||
return navigateTo("/login");
|
|
||||||
}
|
|
||||||
|
|
||||||
// API 권한 체크 (로그인된 사용자만)
|
|
||||||
if (userStore.isLoggedIn) {
|
|
||||||
const currentPath = to.path;
|
|
||||||
if (!permissionsStore.hasApiPermission(currentPath)) {
|
|
||||||
// 권한이 없는 경우 홈으로 리다이렉트
|
|
||||||
return navigateTo("/");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
@@ -72,7 +72,23 @@ export const usePermissionsStore = defineStore(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const hasPagePermission = (page: string): boolean => {
|
const hasPagePermission = (page: string): boolean => {
|
||||||
return getPagePaths().includes(page);
|
const pagePaths = getPagePaths();
|
||||||
|
|
||||||
|
// 1. 정확한 경로 매치 먼저 확인
|
||||||
|
if (pagePaths.includes(page)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 동적 라우팅 패턴 체크
|
||||||
|
for (const allowedPath of pagePaths) {
|
||||||
|
// 동적 라우팅 패턴: /[tabId]/path 형태
|
||||||
|
const dynamicPattern = new RegExp(`^/\\d+${allowedPath}$`);
|
||||||
|
if (dynamicPattern.test(page)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const hasPageGroupPermission = (pageGroup: string): boolean => {
|
const hasPageGroupPermission = (pageGroup: string): boolean => {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ export const useTabsStore = defineStore("tabs", {
|
|||||||
activeTab: 1,
|
activeTab: 1,
|
||||||
}),
|
}),
|
||||||
actions: {
|
actions: {
|
||||||
// 서브메뉴 클릭 시 새 탭 생성 (중복 체크 추가)
|
|
||||||
async updateActiveTab(sub: {
|
async updateActiveTab(sub: {
|
||||||
label: string;
|
label: string;
|
||||||
to: string;
|
to: string;
|
||||||
|
|||||||
@@ -48,27 +48,19 @@ export const useUserStore = defineStore(
|
|||||||
};
|
};
|
||||||
|
|
||||||
const logout = async () => {
|
const logout = async () => {
|
||||||
try {
|
await useApi("/members/logout", {
|
||||||
const response = await useApi("/members/logout", {
|
|
||||||
method: "post",
|
method: "post",
|
||||||
loadingMessage: "로그아웃 처리중...",
|
loadingMessage: "로그아웃 처리중...",
|
||||||
handleError: false,
|
|
||||||
showAlert: false,
|
showAlert: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("response:", response);
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
} finally {
|
|
||||||
user.value = null;
|
user.value = null;
|
||||||
isLoggedIn.value = false;
|
isLoggedIn.value = false;
|
||||||
|
|
||||||
tabsStore.resetTabs();
|
tabsStore.resetTabs();
|
||||||
permissionsStore.clearPermissions();
|
permissionsStore.clearPermissions();
|
||||||
|
|
||||||
// 로그인 페이지로 이동
|
|
||||||
await navigateTo("/login");
|
await navigateTo("/login");
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user