Next.js 13 app目录下如何向服务器组件传递授权令牌?
在Next.js 13 App目录中传递JWT令牌到服务器组件
一、通过Cookie传递(适合服务器组件渲染时直接获取)
如果你需要服务器组件在页面初始渲染时就能拿到令牌,可以在客户端将令牌写入Cookie,服务器组件通过cookies()读取:
客户端设置Cookie
在客户端组件中,从Context获取令牌后,用document.cookie写入:
// 客户端组件(需加'use client'指令) 'use client'; import { useAuthContext } from '../contexts/AuthContext'; import { useEffect } from 'react'; export default function AuthCookieSetter() { const { token } = useAuthContext(); useEffect(() => { if (token) { // 设置Cookie,配置path确保全站可读取,secure和sameSite提升安全性 document.cookie = `authToken=${token}; path=/; secure; sameSite=strict`; } else { // 令牌失效时清除Cookie document.cookie = `authToken=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT`; } }, [token]); return null; // 这个组件只负责设置Cookie,无需渲染内容 }
服务器组件读取Cookie
在服务器组件中,从next/headers导入cookies()获取令牌:
// 服务器组件(app/page.js) import { cookies } from 'next/headers'; export default async function ProtectedPage() { const cookieStore = cookies(); const authToken = cookieStore.get('authToken')?.value; if (!authToken) { return <div>未授权,请登录</div>; } // 使用令牌请求受保护的数据源 const res = await fetch('https://your-api.com/protected-data', { headers: { Authorization: `Bearer ${authToken}` } }); const data = await res.json(); return <div>获取到的数据:{JSON.stringify(data)}</div>; }
二、通过请求头传递(可控发送时机,推荐你的需求)
因为浏览器页面导航请求的头无法自定义,所以要通过客户端发起API请求的方式带令牌,服务器端在API路由中用headers()读取:
客户端发起带请求头的API请求
在客户端组件中,从Context拿到令牌后,用fetch请求API路由时携带授权头:
// 客户端组件(需加'use client'指令) 'use client'; import { useAuthContext } from '../contexts/AuthContext'; import { useState, useEffect } from 'react'; export default function DataFetcher() { const { token } = useAuthContext(); const [protectedData, setProtectedData] = useState(null); const [error, setError] = useState(null); useEffect(() => { const fetchProtectedData = async () => { if (!token) { setError('未获取到授权令牌'); return; } try { const res = await fetch('/api/protected-data', { headers: { Authorization: `Bearer ${token}` } }); if (!res.ok) throw new Error('请求失败'); const data = await res.json(); setProtectedData(data); } catch (err) { setError(err.message); } }; fetchProtectedData(); }, [token]); if (error) return <div>错误:{error}</div>; if (!protectedData) return <div>加载中...</div>; return <div>受保护数据:{JSON.stringify(protectedData)}</div>; }
API路由读取请求头
在app/api/protected-data/route.js中,用headers()获取授权头并处理:
// API路由(服务器端运行) import { headers } from 'next/headers'; export async function GET() { const headersList = headers(); const authHeader = headersList.get('authorization'); const token = authHeader?.split(' ')[1]; // 提取Bearer后的令牌 if (!token) { return new Response(JSON.stringify({ error: '未授权' }), { status: 401 }); } // 用令牌请求后端服务 const res = await fetch('https://your-api.com/protected-data', { headers: { Authorization: `Bearer ${token}` } }); if (!res.ok) { return new Response(JSON.stringify({ error: '数据源请求失败' }), { status: res.status }); } const data = await res.json(); return new Response(JSON.stringify(data), { status: 200 }); }
关键注意点
headers()和cookies()只能在服务器组件或API路由中使用,不能在客户端组件调用。- 请求头方案仅适用于客户端主动发起的API请求,无法让服务器组件在页面初始渲染时直接拿到令牌(除非配合Cookie)。
- Cookie方案会随所有请求自动发送,适合需要服务器组件在页面渲染阶段就获取令牌的场景,但要注意Cookie的安全配置(
secure、sameSite、httpOnly可选,httpOnly的话客户端无法读取,更安全)。
内容的提问来源于stack exchange,提问作者dayuloli
相关产品推荐
相关产品推荐

