You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 13:30:36