NextJS 13如何设置受保护路由?JWT实现后仍遇访问问题
解决Next.js受保护路由服务器错误及认证失效问题
问题分析
你遇到的服务器错误大概率是Next.js SSR特性导致的认证逻辑不兼容,加上原高阶组件未处理服务器端场景:
- 服务器端无法读取浏览器
document.cookie,原getTokenCookie在SSR时拿不到值,导致组件返回null引发错误 - 仅靠客户端
useEffect无法阻止服务器端渲染受保护页面的内容,用户直接输入URL仍能看到页面初始渲染结果 - 可能存在导入路径错误或组件命名不规范的问题
修复方案
1. 先排查基础错误
- 检查导入路径:确保
student.js中withAuth的导入路径正确,比如页面在pages/目录下,工具函数在utils/,则导入应为:import withAuth from '../utils/withAuth' - 规范组件命名:React组件需首字母大写,将
const student = () => { ... }改为const Student = () => { ... },导出时用export default withAuth(Student)
2. 重写适配SSR的withAuth高阶组件
Next.js的SSR场景下,必须在服务器端完成认证校验,不能仅依赖客户端useEffect。修改utils/withAuth.js如下:
import { useEffect } from 'react'; import Router from 'next/router'; import { getTokenCookie, isAuthenticated } from './auth'; const withAuth = (WrappedComponent) => { const Auth = (props) => { // 客户端二次校验(防止token在客户端过期) useEffect(() => { if (!isAuthenticated()) { Router.push('/'); } }, []); return <WrappedComponent {...props} />; }; // 服务器端认证校验核心逻辑 Auth.getServerSideProps = async (context) => { // 从请求头中解析Cookie(服务器端无法用document.cookie) const token = getTokenCookie(context.req); if (!token || !isAuthenticated(token)) { return { redirect: { destination: '/', permanent: false, }, }; } // 如果页面本身有getServerSideProps,保留原有逻辑 if (WrappedComponent.getServerSideProps) { const componentProps = await WrappedComponent.getServerSideProps(context); return { ...componentProps }; } return { props: {} }; }; return Auth; }; export default withAuth;
3. 修改auth.js支持服务器端Cookie获取
安装cookie包用于服务器端解析Cookie:
npm install cookie
然后更新utils/auth.js:
import cookie from 'cookie'; // 支持服务器端和客户端获取token export const getTokenCookie = (req = null) => { if (req) { // 服务器端从请求头解析Cookie const cookies = cookie.parse(req.headers.cookie || ''); return cookies.token || null; // 替换为你的Cookie名称 } else { // 客户端解析document.cookie const cookieMap = document.cookie.split(';').reduce((acc, item) => { const [name, value] = item.trim().split('='); acc[name] = value; return acc; }, {}); return cookieMap.token || null; } }; // 完善JWT认证逻辑(需替换为你的实际验证逻辑) export const isAuthenticated = (token = null) => { const authToken = token || getTokenCookie(); if (!authToken) return false; // 示例:用jsonwebtoken包验证token有效性 // import jwt from 'jsonwebtoken'; // try { // jwt.verify(authToken, process.env.JWT_SECRET); // return true; // } catch (err) { // return false; // } // 临时:仅检查token是否存在(上线前必须替换为真实验证) return !!authToken; };
4. 简化方案:直接在页面中使用getServerSideProps
如果不想用高阶组件,可直接在student.js中添加服务器端校验:
import { getTokenCookie, isAuthenticated } from '../utils/auth'; const Student = () => { return <div>学生专属页面</div>; }; export async function getServerSideProps(context) { const token = getTokenCookie(context.req); if (!token || !isAuthenticated(token)) { return { redirect: { destination: '/', permanent: false, }, }; } return { props: {} }; } export default Student;
关键说明
- 服务器端校验是核心:仅靠客户端
useEffect无法阻止用户直接通过URL访问受保护页面,必须在SSR阶段就完成重定向 - Cookie的跨端处理:服务器端只能从请求头中读取Cookie,不能用浏览器的
document.cookie,必须做兼容处理 - JWT验证:上线前一定要完善
isAuthenticated中的JWT签名和有效期验证,不能仅检查token是否存在
内容的提问来源于stack exchange,提问作者Jayanti
相关产品推荐
相关产品推荐

