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

Next.js 13中如何解决页面刷新时NextAuth的登录闪屏问题?

Next.js 13 + NextAuth 解决刷新/启动时显示登录界面的方案

你现在的问题是:应用启动或刷新时,会先显示登录保护的提示,之后才切换到已登录状态。在Next.js 12里你用getStaticProps()提前获取会话来避免这个问题,下面是Next.js 13里的对应实现方式,分两种路由场景说明:

你的现有代码

登录保护页面

import { useSession, signIn, signOut } from "next-auth/react";

function Admin() {
  const { data: session, status } = useSession();
  
  return (
    <div>
      {!session ? (
        <div onClick={() => signIn()}>Login please</div> :
        <div> welcome back </div>
      )}
    </div>
  )
}

Auth Provider

"use client";
import React from "react";
import { SessionProvider } from "next-auth/react";
import { ChakraProvider } from "@chakra-ui/react";

export function AuthProvider({ children }) {
  return (
    <SessionProvider>
      <ChakraProvider>{children}</ChakraProvider>
    </SessionProvider>
  );
}

解决方案

1. 用 Pages Router(和Next.js12路由结构一致)

直接用getServerSideProps在服务端提前校验会话,没有会话就重定向,避免客户端渲染空状态:

import { getSession } from "next-auth/react";
import { useSession, signOut } from "next-auth/react";

function Admin() {
  const { data: session } = useSession();
  
  return (
    <div>
      <div> welcome back </div>
      <button onClick={() => signOut()}>登出</button>
    </div>
  )
}

// 服务端预取会话并校验
export async function getServerSideProps(context) {
  const session = await getSession(context);
  
  if (!session) {
    return {
      redirect: {
        destination: "/api/auth/signin", // 你的登录页地址
        permanent: false,
      },
    };
  }
  
  return {
    props: { session }, // 将会话传给页面组件
  };
}

export default Admin;

这样页面会在服务端完成会话校验,无会话直接跳登录,有会话才渲染页面,彻底避免闪烁。

2. 用 App Router(Next.js13新路由)

App Router里要结合服务端组件和客户端组件来实现:

第一步:服务端组件做会话校验

创建app/admin/page.js(无需加"use client",默认是服务端组件):

import { getServerSession } from "next-auth/next";
import { authOptions } from "../api/auth/[...nextauth]/route"; // 替换成你的auth配置路径
import AdminClient from "./AdminClient";
import { redirect } from "next/navigation";

export default async function AdminPage() {
  const session = await getServerSession(authOptions);
  
  if (!session) {
    redirect("/api/auth/signin"); // 无会话直接跳登录
  }
  
  // 把会话传给客户端组件渲染
  return <AdminClient session={session} />;
}

第二步:客户端组件渲染页面内容

创建app/admin/AdminClient.js(加"use client"标记为客户端组件):

"use client";
import { signOut } from "next-auth/react";

export default function AdminClient({ session }) {
  return (
    <div>
      <div>Welcome back, {session.user.name}</div>
      <button onClick={() => signOut()}>Sign Out</button>
    </div>
  );
}

可选优化:给SessionProvider传初始会话

如果需要在全局客户端组件里用useSession,可以把服务端拿到的会话传给SessionProvider,避免初始空状态:

"use client";
import React from "react";
import { SessionProvider } from "next-auth/react";
import { ChakraProvider } from "@chakra-ui/react";

export function AuthProvider({ children, session }) {
  // 传入初始会话,客户端就不用再重新请求
  return (
    <SessionProvider session={session}>
      <ChakraProvider>{children}</ChakraProvider>
    </SessionProvider>
  );
}

然后在根布局(app/layout.js,服务端组件)里使用:

import { getServerSession } from "next-auth/next";
import { authOptions } from "./api/auth/[...nextauth]/route";
import { AuthProvider } from "./AuthProvider";

export default async function RootLayout({ children }) {
  const session = await getServerSession(authOptions);
  
  return (
    <html lang="en">
      <body>
        <AuthProvider session={session}>{children}</AuthProvider>
      </body>
    </html>
  );
}

注意事项

  • 无论哪种路由模式,必须在服务端做会话校验,不能只依赖客户端的useSession,防止用户篡改客户端数据绕过权限。
  • 服务端预取会话是解决初始状态闪烁的最优方案,从根源避免了客户端先渲染空状态的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 19:01:28