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

使用AuthJS(V5)登录后首次渲染用户角色为undefined的问题

问题根源

登录后首次渲染侧边栏时session?.role返回undefined,核心原因是AuthJS的session状态还未完成同步,组件就提前渲染了。刷新浏览器后session已持久化到本地存储,因此能正常读取角色信息。

解决办法

1. 调整Provider嵌套顺序

确保SessionProvider包裹React Query的QueryClientProvider,保证session初始化优先级更高:

// app/layout.tsx
import { SessionProvider } from "next-auth/react"
import { QueryClientProvider, QueryClient } from "@tanstack/react-query"

const queryClient = new QueryClient()

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <SessionProvider>
          <QueryClientProvider client={queryClient}>
            {children}
          </QueryClientProvider>
        </SessionProvider>
      </body>
    </html>
  )
}

2. 优化useCurrentUser钩子,监听session变化

改造钩子使其监听AuthJS的session状态,在session未就绪时返回加载状态,避免组件获取到undefined:

// hooks/useCurrentUser.ts
import { useSession } from "next-auth/react"
import { useQuery } from "@tanstack/react-query"

export function useCurrentUser() {
  const { data: session, status } = useSession()

  // session加载中时,直接返回加载状态
  if (status === "loading") {
    return { user: null, isLoading: true }
  }

  // 以session用户ID为依赖,触发react-query查询
  const { data: user } = useQuery({
    queryKey: ["currentUser", session?.user?.id],
    queryFn: async () => {
      if (!session?.user?.id) throw new Error("无有效用户session")
      const res = await fetch(`/api/users/${session.user.id}`)
      return res.json()
    },
    enabled: !!session?.user?.id // 仅当session存在时触发查询
  })

  return { user, isLoading: status === "loading" || !user }
}

3. 侧边栏组件处理加载状态

在AppSidebar中先判断加载状态,等用户数据就绪后再渲染对应角色的菜单:

// components/AppSidebar.tsx
import { useCurrentUser } from "@/hooks/useCurrentUser"

export default function AppSidebar() {
  const { user, isLoading } = useCurrentUser()

  if (isLoading) {
    return <div>加载中...</div> // 可替换为骨架屏提升体验
  }

  if (!user) {
    return <div>请先登录</div>
  }

  return (
    <aside>
      {user.role === "admin" ? (
        <div>
          <h3>管理员菜单</h3>
          <ul>
            <li>用户管理</li>
            <li>系统设置</li>
          </ul>
        </div>
      ) : (
        <div>
          <h3>普通用户菜单</h3>
          <ul>
            <li>个人中心</li>
            <li>我的订单</li>
          </ul>
        </div>
      )}
    </aside>
  )
}

4. 确保AuthJS的session包含role字段

检查AuthJS配置,在session回调中把用户role挂载到session对象上:

// app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth"
import CredentialsProvider from "next-auth/providers/credentials"

const handler = NextAuth({
  providers: [
    CredentialsProvider({
      async authorize(credentials) {
        // 从数据库查询用户,需包含role字段
        const user = await db.user.findUnique({
          where: { email: credentials?.email }
        })
        return user
      }
    })
  ],
  callbacks: {
    async session({ session, user }) {
      // 将用户role添加到session中
      session.user.role = user.role
      return session
    }
  }
})

export { handler as GET, handler as POST }

5. 登录成功后手动刷新session(可选)

若仍存在状态同步延迟,可在登录成功后手动触发session刷新:

// 登录组件示例
import { signIn, getSession } from "next-auth/react"

async function handleLogin() {
  const result = await signIn("credentials", {
    email: "admin@example.com",
    password: "123456",
    redirect: false
  })

  if (result?.ok) {
    // 登录成功后强制刷新session
    await getSession()
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 04:42:18