auto commit

This commit is contained in:
bangdk 2024-11-14 15:20:02 +09:00
parent c07c2a537f
commit 35e2a31442
6 changed files with 211 additions and 116 deletions

View File

@ -1,13 +1,10 @@
// src/app/(admin)/layout.tsx // src/app/(admin)/layout.tsx
import React from "react";
import AdminGuard from "@/components/auth/AdminGuard"; import AdminGuard from "@/components/auth/AdminGuard";
import { SideNav } from "@/components/layout/SideNav"; import { SideNav } from "@/components/layout/SideNav";
import { TopNav } from "@/components/layout/TopNav"; import { TopNav } from "@/components/layout/TopNav";
export default function AdminLayout({ const AdminLayout = ({ children }: { children: React.ReactNode }) => {
children,
}: {
children: React.ReactNode;
}) {
return ( return (
<AdminGuard> <AdminGuard>
<div className="h-screen flex"> <div className="h-screen flex">
@ -29,4 +26,6 @@ export default function AdminLayout({
</div> </div>
</AdminGuard> </AdminGuard>
); );
} };
export default AdminLayout;

View File

@ -22,6 +22,7 @@ import { AxiosError } from "axios";
import { UserForm } from "./components/UserForm"; import { UserForm } from "./components/UserForm";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { User } from "@/types/user"; import { User } from "@/types/user";
import AdminGuard from "@/components/auth/AdminGuard";
const AccountsPage = () => { const AccountsPage = () => {
const { token, user } = useAuthStore(); const { token, user } = useAuthStore();
@ -225,6 +226,7 @@ const AccountsPage = () => {
if (isLoading) return <div>Loading...</div>; if (isLoading) return <div>Loading...</div>;
return ( return (
<AdminGuard requiredPermissions={["users:manage"]}>
<div className="container mx-auto py-6"> <div className="container mx-auto py-6">
{/* Header */} {/* Header */}
<div className="flex justify-between items-center mb-6"> <div className="flex justify-between items-center mb-6">
@ -290,6 +292,7 @@ const AccountsPage = () => {
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</div> </div>
</AdminGuard>
); );
}; };

View File

@ -1,13 +1,52 @@
// // src/components/auth/AdminGuard.tsx
// "use client";
// import { usePermissions } from "@/hooks/usePermissions";
// import { ReactNode } from "react";
// interface AdminGuardProps {
// children: ReactNode;
// requiredPermissions?: string[]; // 필요한 권한 목록
// requireAll?: boolean; // true면 모든 권한 필요, false면 하나라도 있으면 됨
// }
// export default function AdminGuard({
// children,
// requiredPermissions = [],
// requireAll = false,
// }: AdminGuardProps) {
// const { hasAllPermissions, hasAnyPermission } = usePermissions();
// const hasAccess =
// requiredPermissions.length === 0
// ? true
// : requireAll
// ? hasAllPermissions(requiredPermissions)
// : hasAnyPermission(requiredPermissions);
// if (!hasAccess) {
// return (
// <div className="flex items-center justify-center min-h-[200px] text-gray-500">
// 접근 권한이 없습니다.
// </div>
// );
// }
// return <>{children}</>;
// }
// src/components/auth/AdminGuard.tsx // src/components/auth/AdminGuard.tsx
"use client"; "use client";
import { useEffect } from "react";
import { useRouter } from "next/navigation";
import { usePermissions } from "@/hooks/usePermissions"; import { usePermissions } from "@/hooks/usePermissions";
import { ReactNode } from "react"; import { useAuth } from "@/hooks/useAuth";
interface AdminGuardProps { interface AdminGuardProps {
children: ReactNode; children: React.ReactNode;
requiredPermissions?: string[]; // 필요한 권한 목록 requiredPermissions?: string[];
requireAll?: boolean; // true면 모든 권한 필요, false면 하나라도 있으면 됨 requireAll?: boolean;
} }
export default function AdminGuard({ export default function AdminGuard({
@ -15,8 +54,18 @@ export default function AdminGuard({
requiredPermissions = [], requiredPermissions = [],
requireAll = false, requireAll = false,
}: AdminGuardProps) { }: AdminGuardProps) {
const router = useRouter();
const { user } = useAuth();
const { hasAllPermissions, hasAnyPermission } = usePermissions(); const { hasAllPermissions, hasAnyPermission } = usePermissions();
useEffect(() => {
// 사용자가 없거나 로그인하지 않은 경우
if (!user) {
router.push("/login");
return;
}
// 권한 체크
const hasAccess = const hasAccess =
requiredPermissions.length === 0 requiredPermissions.length === 0
? true ? true
@ -25,19 +74,32 @@ export default function AdminGuard({
: hasAnyPermission(requiredPermissions); : hasAnyPermission(requiredPermissions);
if (!hasAccess) { if (!hasAccess) {
router.push("/dashboard/overview");
}
}, [
user,
router,
requiredPermissions,
requireAll,
hasAllPermissions,
hasAnyPermission,
]);
// 권한 체크
const hasAccess =
requiredPermissions.length === 0
? true
: requireAll
? hasAllPermissions(requiredPermissions)
: hasAnyPermission(requiredPermissions);
if (!user || !hasAccess) {
return ( return (
<div className="flex items-center justify-center min-h-[200px] text-gray-500"> <div className="flex items-center justify-center min-h-[200px] text-gray-500">
. ...
</div> </div>
); );
} }
return <>{children}</>; return <>{children}</>;
} }
// 사용 예시:
/*
<AdminGuard requiredPermissions={['users:manage']}>
<UserManagementPanel />
</AdminGuard>
*/

View File

@ -37,7 +37,7 @@ export function useAuth() {
const logout = () => { const logout = () => {
clearAuth(); clearAuth();
localStorage.removeItem("token"); localStorage.removeItem("token");
router.push("/"); router.push("/login");
}; };
return { user, token, login, logout }; return { user, token, login, logout };

View File

@ -1,39 +1,70 @@
// // src/hooks/usePermissions.ts
// import { useAuth } from "./useAuth";
// export function usePermissions() {
// const { user } = useAuth();
// const permissions = user?.permissions || {};
// const hasPermission = (permission: string): boolean => {
// return !!permissions[permission];
// };
// const hasAnyPermission = (requiredPermissions: string[]): boolean => {
// return requiredPermissions.some((permission) => hasPermission(permission));
// };
// const hasAllPermissions = (requiredPermissions: string[]): boolean => {
// return requiredPermissions.every((permission) => hasPermission(permission));
// };
// return {
// permissions,
// hasPermission,
// hasAnyPermission,
// hasAllPermissions,
// };
// }
// src/hooks/usePermissions.ts // src/hooks/usePermissions.ts
import { useAuth } from "./useAuth"; import { useAuth } from "./useAuth";
import { PATH_PERMISSIONS } from "@/config/permissions";
export function usePermissions() { export function usePermissions() {
const { user } = useAuth(); const { user } = useAuth();
const permissions = user?.permissions || {}; const permissions = user?.permissions || {};
const hasPermission = (permission: string): boolean => { const hasPermission = (permission: string): boolean => {
if (!user) return false;
// 슈퍼 관리자는 모든 권한을 가짐
if (user.role === "super_admin") return true;
// 회사 관리자는 회사 관련 모든 권한을 가짐
if (user.role === "company_admin") {
if (
permission.startsWith("company:") ||
permission.startsWith("branches:") ||
permission.startsWith("users:") ||
permission.startsWith("departments:")
) {
return true;
}
}
return !!permissions[permission]; return !!permissions[permission];
}; };
const hasAnyPermission = (requiredPermissions: string[]): boolean => { const hasPathPermission = (path: string): boolean => {
const requiredPermissions = PATH_PERMISSIONS[path];
if (!requiredPermissions) return true;
return requiredPermissions.some((permission) => hasPermission(permission)); return requiredPermissions.some((permission) => hasPermission(permission));
}; };
const hasAllPermissions = (requiredPermissions: string[]): boolean => {
return requiredPermissions.every((permission) => hasPermission(permission));
};
return { return {
permissions, permissions,
hasPermission, hasPermission,
hasAnyPermission, hasPathPermission,
hasAllPermissions, hasAnyPermission: (perms: string[]) => perms.some(hasPermission),
hasAllPermissions: (perms: string[]) => perms.every(hasPermission),
}; };
} }
// 사용 예시:
/*
function MyComponent() {
const { hasPermission } = usePermissions();
if (!hasPermission('departments:view')) {
return <div> .</div>;
}
return <div> ...</div>;
}
*/

View File

@ -2,14 +2,14 @@
export interface User { export interface User {
id: string; id: string;
username: string; username: string;
role: 'admin' | 'user'; role: "super_admin" | "company_admin" | "branch_admin" | "user";
// ... permissions: Record<string, boolean>;
} }
export interface EnergyUsage { export interface EnergyUsage {
timestamp: string; timestamp: string;
value: number; value: number;
type: 'electricity' | 'gas' | 'water' | 'steam'; type: "electricity" | "gas" | "water" | "steam";
} }
// ... // ...