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
相关产品推荐
相关产品推荐

