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

NextJS外部链接访问时显示已登出问题排查

问题描述

网站右上角的用户栏组件,登录时显示用户名,未登录显示「Sign In」链接。但通过外部网站链接访问时,页面显示「Sign In」,网站判定未登录;刷新页面后又显示已登录状态(此时nxtCookies.getAll()为空);直接输入URL访问时登录状态显示正常。

UserInfoBar 组件代码

import React from 'react'
import Link from 'next/link'
import { getSession } from '../../lib/session'

export default async function UserInfoBar() {
    let sessionData = await getSession();

    return (
                {
                    Object.keys(sessionData).length > 0 ?
                            {sessionData.username}: <Link href='/signin'>Sign In</Link>
                }
    )
}

session 工具代码

import { cookies } from 'next/headers';
import prisma from './prisma'
import jwt from 'jsonwebtoken'

export const getSession = async () => {
    const nxtCookies = cookies();

    if (nxtCookies.has('wp_session')) {
        let sessionData = jwt.verify(nxtCookies.get('wp_session').value, process.env.ACCESS_TOKEN_SECRET, async (err, user) => {
            if (!err) {
                let r = await prisma.user.findUnique({
                    where: {
                        id: user.id
                    }
                });

                if (r) {
                    return {
                        id: r?.id,
                        email: r?.email,
                        username: r?.username
                    };
                }
            }

            return false;
        });

        if (sessionData) return sessionData;
    }

    return false;
}

登录时设置Cookie的代码

setCookie('wp_session', token, {
    path: '/',
    maxAge: 3600 * 24 * 7 * 30,
    sameSite: true
});
问题原因及解决方案

1. SameSite Cookie配置错误

设置Cookie时sameSite: true不符合规范,Next.js的setCookie方法中,sameSite的合法值为字符串:'strict'、'lax'、'none',布尔值会被浏览器判定为无效配置。

从外部网站跳转属于跨站请求,若SameSite配置不正确,浏览器不会携带Cookie到服务端,导致getSession拿不到wp_session,显示未登录;而刷新页面是同站请求,浏览器会携带Cookie,因此能正确识别登录状态。

修复方案:
根据业务需求调整SameSite值:

  • 若允许跨站GET请求携带Cookie,设置为'lax'(默认推荐值)
  • 若需支持第三方嵌入场景,设置为'none'(需同时开启secure: true,仅HTTPS环境生效)
setCookie('wp_session', token, {
    path: '/',
    maxAge: 3600 * 24 * 7 * 30,
    sameSite: 'lax',
    // 若使用sameSite: 'none',需添加以下配置
    // secure: process.env.NODE_ENV === 'production'
});

2. jwt.verify异步回调使用错误

jwt.verify的回调是异步执行的,但你直接将jwt.verify的返回值赋值给sessionData,而该方法在使用回调时返回的是undefined,无法获取异步验证后的用户数据,导致sessionData始终为undefined,最终返回false。

修复方案:
改用同步方式验证JWT,避免异步回调导致的取值错误:

export const getSession = async () => {
    const nxtCookies = cookies();

    if (nxtCookies.has('wp_session')) {
        try {
            // 同步验证JWT
            const user = jwt.verify(nxtCookies.get('wp_session').value, process.env.ACCESS_TOKEN_SECRET);
            // 查询用户信息
            const userInfo = await prisma.user.findUnique({
                where: { id: user.id }
            });
            if (userInfo) {
                return {
                    id: userInfo.id,
                    email: userInfo.email,
                    username: userInfo.username
                };
            }
        } catch (err) {
            // 处理JWT验证失败、用户不存在等异常
            return false;
        }
    }

    return false;
}

3. 服务端组件与客户端状态同步问题

UserInfoBar作为服务端组件,首次从外部链接访问时,服务端因Cookie未携带而渲染「Sign In」;刷新时服务端能拿到Cookie,渲染用户名。若需要客户端也能实时获取登录状态,可结合document.cookie读取客户端Cookie,或使用SWR/React Query做状态同步,但优先解决前两个核心问题即可覆盖大部分场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 00:10:47