Next.js Layout层级JWT鉴权及localStorage读取问题求助
解决方案:Next.js 根Layout全局JWT权限控制
1. 修正客户端权限校验工具函数
你之前的IsAuth函数存在笔误(windows应为window),且需添加'use client'标记——因为要访问浏览器的localStorage,必须用客户端组件实现:
'use client'; import { useState, useEffect } from 'react'; export const useIsAuth = () => { const [isAuthenticated, setIsAuthenticated] = useState<boolean | null>(null); useEffect(() => { // 仅在浏览器环境执行 if (typeof window === 'undefined') return; const jwtToken = localStorage.getItem('ltu'); // 不仅判断token存在,还要验证有效性(推荐) const isValidToken = validateJwtToken(jwtToken); setIsAuthenticated(isValidToken); }, []); return isAuthenticated; }; // 辅助函数:验证JWT有效性(解析payload+检查过期时间) const validateJwtToken = (token: string | null): boolean => { if (!token) return false; try { const payload = JSON.parse(atob(token.split('.')[1])); // exp是JWT自带的过期时间戳(单位秒),转毫秒后对比当前时间 return payload.exp * 1000 > Date.now(); } catch (err) { return false; } };
2. 全局权限守卫组件
编写客户端组件AuthGuard,统一处理路由权限判断,避免每个页面重复写校验逻辑:
'use client'; import { useEffect } from 'react'; import { useRouter, usePathname } from 'next/navigation'; import { useIsAuth } from './useIsAuth'; // 允许未登录访问的路由白名单 const PUBLIC_ROUTES = ['/', '/login', '/register']; export const AuthGuard = ({ children }: { children: React.ReactNode }) => { const isAuthenticated = useIsAuth(); const router = useRouter(); const pathname = usePathname(); useEffect(() => { // 等待权限状态加载完成再判断 if (isAuthenticated === null) return; // 非白名单路由且未登录,跳转到登录页 if (!isAuthenticated && !PUBLIC_ROUTES.includes(pathname)) { router.push('/login'); } // 已登录但访问登录/注册页,自动跳转到首页(可选) if (isAuthenticated && PUBLIC_ROUTES.includes(pathname)) { router.push('/dashboard'); } }, [isAuthenticated, pathname, router]); // 权限状态未加载完成时,可显示加载占位(可选) if (isAuthenticated === null) { return <div>加载中...</div>; } return children; };
3. 在根Layout中挂载全局守卫
根Layout是所有页面的顶层容器,直接引入AuthGuard包裹所有页面内容,即可实现全局权限控制:
// app/layout.tsx(根Layout文件) import { AuthGuard } from './components/AuthGuard'; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="zh-CN"> <body> {/* 全局权限守卫,所有页面都会经过这里校验 */} <AuthGuard>{children}</AuthGuard> </body> </html> ); }
核心说明
- Next.js 根Layout默认是服务器组件,无法访问浏览器API(如
localStorage),因此权限校验逻辑必须放在标记'use client'的客户端组件中。 - 通过根Layout挂载
AuthGuard,无需在每个页面单独编写权限校验代码,实现统一控制。 - JWT校验不能仅判断存在性,必须验证过期时间,避免使用无效/过期的token。
内容的提问来源于stack exchange,提问作者Skinsky Gnudy
相关产品推荐
相关产品推荐

