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

NextJS 13.4中使用Next-Auth登录时出现Hydration错误

问题复现步骤
  • 环境版本:
    • node -v -> v18.16.1
    • npx -v -> 9.8.0
  • 使用npx create-next-app@latest创建基于App目录的Next.js应用
  • 通过npm i next-auth安装NextAuth
  • 核心实现代码:
    1. NextAuth路由代码:
    import { authOptions } from "@/app/options/authOptions";
    import NextAuth from "next-auth/next";
    
    const handler = NextAuth(authOptions)
    
    export { handler as GET, handler as POST }
    
    1. 客户端Session Provider:
    "use client";
    
    import React from "react";
    import { SessionProvider } from "next-auth/react";
    
    interface Props {
        children?: React.ReactNode;
    }
    
    export default function NextAuthSessionProvider({ children }: Props) {
        return (
            <SessionProvider>
                { children }
            </SessionProvider>
        )
    }
    
    1. Auth配置选项:
    interface User {
        id: string;
        name: string;
        email: string;
    }
    
    export const authOptions: NextAuthOptions = {
      providers: [
        Credentials({
          name: "Credentials",
          credentials: {
            username: { label: "Username", type: "text", placeholder: "jsmith" },
            password: { label: "Password", type: "password" }
          },
          async authorize(credentials, req): Promise<User | null> {
            if (credentials?.username === "a" && credentials?.password === "b") {
              return { id: "1", name: "John Smith", email: "john@example.com" };
            } else {
              return null;
            }
          }
        })
      ]
    }
    
    1. Root Layout代码:
    const inter = Inter({ subsets: ['latin'] })
    
    export const metadata: Metadata = {
      title: 'Create Next App',
      description: 'Generated by create next app',
    }
    
    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode
    }) {
      return (
        <html lang="en">
          <body className={inter.className}>
            <NextAuthSessionProvider>{children}</NextAuthSessionProvider>
          </body>
        </html>
      )
    }
    
    1. 首页代码:
    import Link from 'next/link';
    
    export default function Home() {
      return (
        <div>
          <h1>Home</h1>
          <Link href={'/dashboard'}>
            Dashboard
          </Link>
          <br />
          <Link href={'/api/auth/signin'}>
            Sign in
          </Link>
          <br />
          <Link href={'/api/auth/signout'}>
            Sign out
          </Link>
        </div>
      )
    }
    
    1. 受保护的Dashboard页面:
    export default async function DashboardPage() {
      const session = await getServerSession(authOptions);
    
      if (!session) {
        redirect('/api/auth/signin');
      }
    
      return (
        <div>
          <h1>Dashboard</h1>
          <p>
            This page is only accessible to signed-in users.
          </p>
          <Link href={'/'}>
            Home
          </Link>
          <br />
          <Link href={'/api/auth/signout'}>
            Sign out
          </Link>
        </div>
      )
    }
    
错误情况

点击首页的Dashboard链接,会被重定向到/api/auth/signin,输入用户名a、密码b完成登录后,未跳转到预期的/dashboard,反而回到首页/,同时页面出现三个错误。


解决方案

1. 完善Auth配置选项

修改authOptions,补充Session策略、回调函数,确保登录后重定向逻辑和Session序列化正常:

import { NextAuthOptions, CredentialsProvider, Session } from "next-auth";
import { JWT } from "next-auth/jwt";

interface User {
  id: string;
  name: string;
  email: string;
}

export const authOptions: NextAuthOptions = {
  providers: [
    Credentials({
      name: "Credentials",
      credentials: {
        username: { label: "Username", type: "text", placeholder: "jsmith" },
        password: { label: "Password", type: "password" }
      },
      async authorize(credentials, req): Promise<User | null> {
        if (credentials?.username === "a" && credentials?.password === "b") {
          return { id: "1", name: "John Smith", email: "john@example.com" };
        } else {
          return null;
        }
      }
    })
  ],
  // 指定Session存储策略为JWT
  session: {
    strategy: "jwt"
  },
  // 处理Session和JWT的序列化,以及登录重定向逻辑
  callbacks: {
    async jwt({ token, user }): Promise<JWT> {
      if (user) {
        token.id = user.id;
        token.name = user.name;
        token.email = user.email;
      }
      return token;
    },
    async session({ session, token }): Promise<Session> {
      if (session.user) {
        session.user.id = token.id as string;
        session.user.name = token.name as string;
        session.user.email = token.email as string;
      }
      return session;
    },
    async signIn({ user, callbackUrl }) {
      if (user) {
        // 登录成功后跳转到原本的目标页面,无目标则默认首页
        return callbackUrl || "/";
      }
      return false;
    }
  },
  pages: {
    signIn: "/api/auth/signin"
  }
};

2. 修改Dashboard页面的重定向逻辑

重定向到登录页时,传递当前页面URL作为回调地址:

import { redirect } from "next/navigation";
import { getServerSession } from "next-auth";
import { authOptions } from "@/app/options/authOptions";

export default async function DashboardPage() {
  const session = await getServerSession(authOptions);

  if (!session) {
    // 传递当前页面作为登录后的跳转目标
    redirect(`/api/auth/signin?callbackUrl=${encodeURIComponent("/dashboard")}`);
  }

  return (
    <div>
      <h1>Dashboard</h1>
      <p>
        This page is only accessible to signed-in users.
      </p>
      <Link href={'/'}>
        Home
      </Link>
      <br />
      <Link href={'/api/auth/signout'}>
        Sign out
      </Link>
    </div>
  )
}

3. 清除缓存并重启服务

执行以下命令确保配置生效:

npm run build
npm run dev

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 23:42:31