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

Next.js 13新app目录下SSR认证:如何传递用户对象至子组件

解决方案与改进建议

核心思路:服务器组件Props传递(无需use client)

在Next.js App Router中,布局默认是服务器组件,可以直接异步获取用户数据,再通过Props层层传递给所有子组件,完全避开客户端状态管理(如Context),实现纯SSR认证,页面加载时直接渲染用户信息。

1. 布局中获取用户并传递给子组件

在根布局(或共享布局)中调用你的服务器函数获取用户,通过React.cloneElement将用户数据注入所有子页面/组件的Props:

// app/layout.tsx - 默认服务器组件,无需"use client"
import { cookies } from 'next/headers'
import { redirect } from 'next/navigation'
import { getUserDetails } from '@/lib/server-utils' // 你的用户获取函数

export default async function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  // 从HttpOnly Cookie获取认证Token(推荐用Cookie而非请求头,更安全)
  const authToken = cookies().get('auth-token')?.value
  let user = null

  if (authToken) {
    try {
      user = await getUserDetails(authToken)
    } catch (err) {
      // Token无效时清除Cookie并重定向登录页
      cookies().delete('auth-token')
      redirect('/login')
    }
  }

  // 未登录且非登录页时重定向
  const pathname = request.nextUrl.pathname
  if (!user && pathname !== '/login') {
    redirect('/login')
  }

  // 将用户数据注入所有子元素的Props
  const childrenWithUser = React.Children.map(children, child => {
    if (React.isValidElement(child)) {
      return React.cloneElement(child, { user })
    }
    return child
  })

  return (
    <html lang="zh-CN">
      <body>{childrenWithUser}</body>
    </html>
  )
}

2. 子组件/页面接收用户数据

所有子页面、组件(服务器组件)可以直接通过Props接收用户数据,无需任何客户端指令:

// app/dashboard/page.tsx - 服务器组件
export default function DashboardPage({ user }) {
  return (
    <div>
      <h1>欢迎回来,{user.nickname}</h1>
      <UserProfile user={user} />
    </div>
  )
}

// 子组件(服务器组件)
function UserProfile({ user }) {
  return <p>绑定邮箱:{user.email}</p>
}

改进方案:用Server Action管理Cookie

你之前修改Cookie失败是因为仅能在Server Action/Route Handler中操作Cookie,登录时用Server Action设置HttpOnly Cookie,安全性更高:

// app/actions/login.ts
'use server'

import { cookies } from 'next/headers'
import { authenticateUser } from '@/lib/server-utils' // 你的登录验证函数

export async function login(credentials: { username: string; password: string }) {
  const user = await authenticateUser(credentials)
  if (!user) return { success: false, error: '账号或密码错误' }

  // 设置HttpOnly、Secure的认证Cookie
  cookies().set('auth-token', user.token, {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    maxAge: 60 * 60 * 24 * 7, // 有效期7天
    path: '/',
  })

  return { success: true }
}

性能优化:服务器端缓存用户数据

为避免每次请求都调用数据库,可在服务器端用Redis等工具缓存用户信息,以Token为Key缓存5-10分钟:

// @/lib/server-utils.ts
import Redis from 'ioredis'
const redis = new Redis(process.env.REDIS_URL)

export async function getUserDetails(token: string) {
  // 先查缓存
  const cachedUser = await redis.get(`user:${token}`)
  if (cachedUser) return JSON.parse(cachedUser)

  // 缓存未命中则查数据库
  const user = await db.user.findUnique({ where: { token } })
  if (!user) throw new Error('无效Token')

  // 写入缓存
  await redis.set(`user:${token}`, JSON.stringify(user), 'EX', 300) // 5分钟过期

  return user
}

优势总结

  • 纯SSR实现,页面加载时直接渲染用户信息,无认证加载状态
  • 无需use client,完全避开客户端状态管理的复杂度
  • 同一布局下的页面切换不会重复执行用户获取逻辑,提升导航效率
  • HttpOnly Cookie避免XSS攻击,安全性更高

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 23:45:11