2.4 페이지/컴포넌트 가드 훅 구현(usePermission)
This commit is contained in:
24
package-lock.json
generated
24
package-lock.json
generated
@@ -12,6 +12,7 @@
|
||||
"next": "15.5.4",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0",
|
||||
"swr": "^2.3.6",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -3630,6 +3631,15 @@
|
||||
"robust-predicates": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/dequal": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/destr": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz",
|
||||
@@ -6492,6 +6502,19 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/swr": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/swr/-/swr-2.3.6.tgz",
|
||||
"integrity": "sha512-wfHRmHWk/isGNMwlLGlZX5Gzz/uTgo0o2IRuTMcf4CPuPFJZlq0rDaKUx+ozB5nBOReNV1kiOyzMfj+MBMikLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3",
|
||||
"use-sync-external-store": "^1.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.11.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tabbable": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
||||
@@ -6782,7 +6805,6 @@
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz",
|
||||
"integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||
|
||||
@@ -17,10 +17,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@prisma/client": "^6.17.0",
|
||||
"zod": "^3.23.8",
|
||||
"next": "15.5.4",
|
||||
"react": "19.1.0",
|
||||
"react-dom": "19.1.0"
|
||||
"react-dom": "19.1.0",
|
||||
"swr": "^2.3.6",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.2.0",
|
||||
|
||||
18
src/app/api/auth/permissions/route.ts
Normal file
18
src/app/api/auth/permissions/route.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import prisma from "@/lib/prisma";
|
||||
import { getUserIdFromRequest } from "@/lib/auth";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
const userId = getUserIdFromRequest(req);
|
||||
if (!userId) return NextResponse.json({ permissions: [] });
|
||||
const roles = await prisma.userRole.findMany({ where: { userId }, select: { roleId: true } });
|
||||
if (roles.length === 0) return NextResponse.json({ permissions: [] });
|
||||
const roleIds = roles.map((r) => r.roleId);
|
||||
const permissions = await prisma.rolePermission.findMany({
|
||||
where: { roleId: { in: roleIds }, allowed: true },
|
||||
select: { resource: true, action: true },
|
||||
});
|
||||
return NextResponse.json({ permissions });
|
||||
}
|
||||
|
||||
|
||||
24
src/lib/usePermission.ts
Normal file
24
src/lib/usePermission.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
"use client";
|
||||
import useSWR from "swr";
|
||||
|
||||
type Resource = "BOARD" | "POST" | "COMMENT" | "USER" | "ADMIN";
|
||||
type Action = "READ" | "CREATE" | "UPDATE" | "DELETE" | "MODERATE" | "ADMINISTER";
|
||||
|
||||
const fetcher = (url: string) => fetch(url).then((r) => r.json());
|
||||
|
||||
export function usePermission() {
|
||||
const { data } = useSWR<{ permissions: { resource: Resource; action: Action }[] }>(
|
||||
"/api/auth/permissions",
|
||||
fetcher
|
||||
);
|
||||
const perms = data?.permissions ?? [];
|
||||
function can(resource: Resource, action: Action) {
|
||||
return (
|
||||
perms.some((p) => p.resource === "ADMIN" && p.action === "ADMINISTER") ||
|
||||
perms.some((p) => p.resource === resource && p.action === action)
|
||||
);
|
||||
}
|
||||
return { can };
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
2.1 역할·권한 시드(admin/editor/user) 추가 o
|
||||
2.2 권한 enum/매핑 정의(리소스/액션) o
|
||||
2.3 서버 권한 미들웨어 적용(API 보호 라우트 지정) o
|
||||
2.4 페이지/컴포넌트 가드 훅 구현(usePermission)
|
||||
2.4 페이지/컴포넌트 가드 훅 구현(usePermission) o
|
||||
2.5 권한 기반 UI 노출 제어(빠른 액션/관리자 메뉴)
|
||||
|
||||
[로그인/인증]
|
||||
|
||||
Reference in New Issue
Block a user