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

Next.js获取用户Cookie异常求助:已登录却无法读取JWT Cookie

问题描述

自定义登录API,登录成功后将JWT存入用户Cookie,期望实现登录后不再渲染注册和登录链接,但当前代码失效:即便Cookie中存在JWT,console.log输出Cookie时仍显示undefined。


Header组件代码

'use client';
import Link from 'next/link';
import { useState, useEffect } from 'react'; 
export default function Header() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);

  useEffect(() => {
    console.log("useEffect is running...");
    if (typeof window !== 'undefined') {
      const cookies = document.cookie;
      console.log("All cookies:", cookies);
      const token = cookies.split(';').find(cookie => cookie.trim().startsWith('token='));
      console.log("Token from cookies:", token);
      setIsLoggedIn(!!token);
    }
  }, []);
  
  return (
    <header className='bg-white border-b flex justify-between p-4'>
      <div className="flex items-center gap-6">
        <Link href={'/'}>FashionFinder </Link>
        <nav className='flex gap-4'>
          <Link href={'/about'}>About</Link>
          <Link href={'/contact'}>Contact</Link>
          <Link href={'/albums'}>Albums</Link>
        </nav>
      </div>
      <nav className='flex items-center gap-4'>
        {isLoggedIn ? (
          <Link href={'/logout'}>Sign Out</Link>
        ) : (
          <>
            <Link href={'/login'}>Sign In</Link>
            <Link href={'/register'}>Create Account</Link>
          </>
        )}
      </nav>
    </header>
  )
}

Login路由代码(route.js)

import { connect } from "@/dbConfig/dbConfig";
import User from "@/models/userModel";
import { NextRequest, NextResponse } from "next/server";
import bcryptjs from "bcryptjs";
import jwt from "jsonwebtoken";

connect()

export async function POST(request) {
  try{

    const reqBody= await request.json()
    const {email, password} = reqBody;
    console.log(reqBody)
    const lowercasedEmail = email.toLowerCase();

    //check if the user exists
    const user = await User.findOne({email: lowercasedEmail})
    if (!user){
      return NextResponse.json({error:"User does not exist"}, {status: 400})
    }

    //check if valid email format
    const isValidEmail = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
    if (!isValidEmail) {
      return NextResponse.json({ error: "Invalid email format" }, { status: 300 });
    }
  
    //check if the password is correct
    const validPassword = await bcryptjs.compare(password, user.password)
    if (!validPassword){
      return NextResponse.json({error: "Invalid password"}, {status:500})
    }
    //create token data
    const tokenData = {
      id: user._id,
      email: user.email
    }
    //create token
    const token = await jwt.sign(tokenData, process.env.TOKEN_SECRET, {expiresIn: "1d"})

    const response = NextResponse.json({
      message: "Login successful",
      success: true
    })
    response.cookies.set("token", token, {
      httpOnly: true
    })
    return response;

  } catch (error){
    return NextResponse.json({error: error.message}, {status: 500})
  }
}

解决思路

1. 核心问题:HttpOnly Cookie无法被前端读取

你设置了httpOnly: true的Cookie,前端JavaScript无法通过document.cookie访问这类Cookie,这就是console.log输出undefined的根本原因。HttpOnly是安全属性,不建议直接移除,推荐通过服务器端验证Cookie状态。

2. 解决方案:服务器端校验登录状态

创建一个后端API用于校验登录状态,前端通过调用该API获取登录状态:

步骤1:创建校验API(app/api/auth/me/route.js)

import { connect } from "@/dbConfig/dbConfig";
import jwt from "jsonwebtoken";
import { NextRequest, NextResponse } from "next/server";

connect();

export async function GET(request) {
  try {
    // 服务器端读取HttpOnly Cookie
    const token = request.cookies.get("token")?.value;
    if (!token) {
      return NextResponse.json({ isLoggedIn: false }, { status: 200 });
    }

    // 验证JWT有效性
    jwt.verify(token, process.env.TOKEN_SECRET);
    return NextResponse.json({ isLoggedIn: true }, { status: 200 });
  } catch (error) {
    // 验证失败或其他错误,返回未登录状态
    return NextResponse.json({ isLoggedIn: false }, { status: 200 });
  }
}

步骤2:修改Header组件调用校验API

'use client';
import Link from 'next/link';
import { useState, useEffect } from 'react'; 
import { useRouter } from 'next/navigation';

export default function Header() {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const router = useRouter();

  // 校验登录状态的函数
  const checkLoginStatus = async () => {
    try {
      const res = await fetch('/api/auth/me', { credentials: 'include' });
      const data = await res.json();
      setIsLoggedIn(data.isLoggedIn);
    } catch (error) {
      setIsLoggedIn(false);
    }
  };

  useEffect(() => {
    checkLoginStatus();
    // 监听路由变化,每次页面切换重新校验状态
    const handleRouteChange = () => checkLoginStatus();
    router.events.on('routeChangeComplete', handleRouteChange);

    // 组件卸载时移除监听
    return () => router.events.off('routeChangeComplete', handleRouteChange);
  }, [router]);
  
  return (
    <header className='bg-white border-b flex justify-between p-4'>
      <div className="flex items-center gap-6">
        <Link href={'/'}>FashionFinder </Link>
        <nav className='flex gap-4'>
          <Link href={'/about'}>About</Link>
          <Link href={'/contact'}>Contact</Link>
          <Link href={'/albums'}>Albums</Link>
        </nav>
      </div>
      <nav className='flex items-center gap-4'>
        {isLoggedIn ? (
          <Link href={'/logout'}>Sign Out</Link>
        ) : (
          <>
            <Link href={'/login'}>Sign In</Link>
            <Link href={'/register'}>Create Account</Link>
          </>
        )}
      </nav>
    </header>
  )
}

3. 优化Cookie设置

在Login路由中完善Cookie的安全属性,避免跨域或路径问题:

response.cookies.set("token", token, {
  httpOnly: true,
  path: "/", // 确保全站可访问
  sameSite: "lax", // 防止CSRF
  secure: process.env.NODE_ENV === "production" // 生产环境开启HTTPS传输
})

4. 登录成功后触发路由跳转

在登录页面调用API成功后,执行路由跳转(比如跳转到首页),触发Header组件的状态重新校验:

const handleLogin = async () => {
  const res = await fetch('/api/login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ email, password })
  });
  const data = await res.json();
  if (data.success) {
    router.push('/'); // 跳转触发Header状态更新
  }
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 04:54:53