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

Next.js电商站客户端JWT Cookie获取为undefined问题排查

问题:Cookie中存在JWT令牌,但客户端获取时返回undefined

我使用Next.js和Mongoose搭建了电商网站,通过Cookie存储JWT令牌。在客户端控制台的Application面板中,可以看到名为OursiteJWT的Cookie及对应令牌值:
Cookie截图

但多次测试发现,获取令牌时返回undefined,控制台输出“pas de token”,密钥是正确的。

pages/orders.js 代码

import { useEffect, useState } from "react";
import axios from "axios";
import jwt from "jsonwebtoken";
import cookie from "cookie";

function Orders() {
  const [orders, setOrders] = useState([]);

  useEffect(() => {
    async function fetchOrders() {
      try {
        // 从API获取密钥
        const secretRes = await axios.get("/api/secret");
        const secret = secretRes.data.secret;
        console.log(secret);
        // 从Cookie获取JWT令牌
        const cookies = cookie.parse(document.cookie);
        const token = cookies.OursiteJWT;
        console.log(token);
        // 若无令牌则返回
        if (!token) {
          console.log("pas de token")
          return;
        }

        // 验证JWT令牌
        const decoded = jwt.verify(token, secret);
        const userId = decoded._id;

        // 从API获取用户订单
        const ordersRes = await axios.get(`/api/orders?user_id=${userId}`);
        const orders = ordersRes.data;

        setOrders(orders);
      } catch (error) {
        console.error(error);
      }
    }

    fetchOrders();
  }, []);

  return (
    <div>
      {orders.map((order) => (
        <div key={order._id}>
          <h2>Commande {order._id}</h2>
          <p>Utilisateur: {order.name}</p>
          <p>Adresse: {order.address}</p>
          <p>Ville: {order.city}</p>
          <p>Produits:</p>
          <ul>
            {order.products.map((product) => (
              <li key={product._id}>{product.name}</li>
            ))}
          </ul>
        </div>
      ))}
    </div>
  );
}

export default Orders;

存储令牌的 api/login.js 代码

import {initMongoose} from "../../lib/mongoose";
import User from '../../models/User';
import { sign } from "jsonwebtoken";
import { serialize } from "cookie";

initMongoose()
const secret = process.env.SECRET;

export default async function handler(req,res){
  
  const {email,password}=req.body;
  const user = await User.findOne({email,password});
  
  if(!user){
    res.status(401).json({message: "Impossible de trouver un utilisateur"});
    return;
  }
  else{
    
    const token = sign(
      {
        exp: Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 30, // 30 days
        email: email,
        _id: user._id,
      },
      secret
    );
    const serialised = serialize("OursiteJWT", token, {
      httpOnly: true,
      secure: process.env.NODE_ENV !== "development",
      sameSite: "strict",
      maxAge: 60 * 60 * 24 * 30,
      path: "/",
    });
    
    res.setHeader("Set-Cookie", serialised);
    res.status(200).json({message :"Success!"});
  }
}

问题原因及解决方法

  • 核心原因:设置Cookie时开启了httpOnly: true,该属性会禁止客户端JavaScript访问Cookie,因此document.cookie无法读取到OursiteJWT。

解决思路(二选一):

  1. 调整Cookie属性(不推荐生产环境):
    如果必须在客户端读取令牌,将login.js中的httpOnly改为false:

    const serialised = serialize("OursiteJWT", token, {
      httpOnly: false, // 修改此处
      secure: process.env.NODE_ENV !== "development",
      sameSite: "strict",
      maxAge: 60 * 60 * 24 * 30,
      path: "/",
    });
    

    注意:关闭httpOnly会增加XSS攻击风险,生产环境不建议使用。

  2. 安全最佳实践(推荐):
    不在客户端处理JWT验证和订单请求,改为服务器端完成:

    • 修改/api/orders接口,让它自动从请求Cookie中读取OursiteJWT,验证后返回用户订单
    • 客户端直接调用/api/orders,无需手动获取令牌:
      // pages/orders.js 中fetchOrders修改为:
      async function fetchOrders() {
        try {
          const ordersRes = await axios.get("/api/orders");
          setOrders(ordersRes.data);
        } catch (error) {
          console.error(error);
        }
      }
      
    • 服务器端/api/orders示例:
      import { initMongoose } from "../../lib/mongoose";
      import Order from "../../models/Order";
      import jwt from "jsonwebtoken";
      import cookie from "cookie";
      
      initMongoose();
      const secret = process.env.SECRET;
      
      export default async function handler(req, res) {
        if (req.method !== "GET") {
          return res.status(405).json({ message: "方法不允许" });
        }
        
        // 从请求头Cookie中读取令牌
        const cookies = cookie.parse(req.headers.cookie || "");
        const token = cookies.OursiteJWT;
        
        if (!token) {
          return res.status(401).json({ message: "未授权" });
        }
        
        try {
          const decoded = jwt.verify(token, secret);
          const orders = await Order.find({ user_id: decoded._id });
          res.status(200).json(orders);
        } catch (error) {
          res.status(401).json({ message: "令牌无效" });
        }
      }
      

    这种方式保留了httpOnly的安全特性,避免了客户端处理敏感令牌的风险。


内容的提问来源于stack exchange,提问作者Rip Rip

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 06:41:33