From 6c58a0e59f122fcdf56ec9d35ffb5125bb42a010 Mon Sep 17 00:00:00 2001 From: linxiaoxin Date: Mon, 19 Aug 2024 22:54:52 +0800 Subject: [PATCH] added route gaurd for frontend access control --- app/layout.tsx | 7 +++++++ lib/RouteGuard.ts | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 lib/RouteGuard.ts diff --git a/app/layout.tsx b/app/layout.tsx index 724dc42..49d5160 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -7,12 +7,19 @@ import 'primeicons/primeicons.css'; import '../styles/layout/layout.scss'; import '../styles/demo/Demos.scss'; import { Suspense } from 'react'; +import { usePathname } from 'next/navigation'; +import { RouteGuard } from '@/lib/RouteGuard'; +import { redirect } from 'next/navigation' interface RootLayoutProps { children: React.ReactNode; } export default function RootLayout({ children }: RootLayoutProps) { + const pathname = usePathname(); + if(!RouteGuard.apply(pathname)){ + redirect('/'); + } return ( diff --git a/lib/RouteGuard.ts b/lib/RouteGuard.ts new file mode 100644 index 0000000..5b31fe6 --- /dev/null +++ b/lib/RouteGuard.ts @@ -0,0 +1,51 @@ +'use client'; +import { USER, IS_LOGIN } from '../lib/constants' + +export const RouteGuard = { + + isLogin(){ + if(typeof sessionStorage !== "undefined"){ + return sessionStorage?.getItem(IS_LOGIN) == "true" || false; + } + else{ + return false; + } + }, + loginUser(){ + if(this.isLogin()){ + return JSON.parse(sessionStorage.getItem(USER) || '') as UserProfile; + } + else{ + return null; + } + }, + apply(path: string):boolean{ + if(process.env.NODE_ENV === 'development') return true; + switch(path){ + case '/': + return true; + case '/auth/google': + return true; + case '/auth/access': + return true; + case '/auth/error': + return true; + case '/dashboard': + return true; + case '/quiz': + return this.accessibleBy(['student']); + case '/questions/searchlist': + return this.accessibleBy(['admin', 'tutor']); + case '/questions/topics': + return this.accessibleBy(['admin', 'tutor']); + case '/classes': + return this.accessibleBy(['admin', 'tutor']); + default: + return false; + } + }, + accessibleBy (roles: string[]) { + return this.isLogin() && this.loginUser()?.roles.some(role => roles.includes(role)) || false; + }, + +} \ No newline at end of file