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

Next.js 13如何将客户端PocketBase会话传递至服务端?

解决方案:在Next.js 13 App Router中传递PocketBase会话到服务端

要解决Server Components无法获取PocketBase会话的问题,核心是把客户端存储的会话令牌传递到服务端,让服务端的PocketBase实例能验证用户身份。以下是具体实现步骤:

1. 登录时同步会话到Cookies

客户端登录成功后,除了依赖PocketBase的authStore,还要把令牌写入Next.js的Cookies,这样服务端能读取到。修改你的登录组件:

'use client';
import { useRouter } from "next/navigation";
import { useState } from "react";
import PocketBase from 'pocketbase';

const pb = new PocketBase('https://pockettest.lightin.io');

export default function Page() {
    const [email, setEmail] = useState("breval.lefloch@gmail.com")
    const [password, setPassword] = useState("123456")
    const router = useRouter();

    const handleSubmit = async (e: { preventDefault: () => void; }) => {
        e.preventDefault()
        if (email && password) {
            const authData = await pb.collection('users').authWithPassword(
                email.toString(),
                password.toString(),
            );

            // 将令牌写入Cookies,设置HttpOnly和Secure增强安全性
            document.cookie = `pb_auth=${pb.authStore.token}; path=/; HttpOnly; Secure; SameSite=Lax`;
            
            // 登录成功后跳转
            router.push('/protected');
        }
    }

    return (
        <div className="flex items-center justify-center h-screen">
            <form onSubmit={handleSubmit} method="post" className="bg-white p-6 rounded-lg shadow-md">
                <h2 className="text-lg font-medium mb-4">Login</h2>

                <div className="mb-4">
                    <label htmlFor="email" className="block font-medium mb-2">Email :</label>
                    <input onChange={e => setEmail(e.target.value)}
                           type="text"
                           name="email"
                           value={email.toString()}
                           required
                           className="border border-gray-400 p-2 w-full"
                    />
                </div>

                <div className="mb-4">
                    <label htmlFor="password" className="block font-medium mb-2">Password :</label>
                    <input onChange={e => setPassword(e.target.value)}
                           type="password"
                           name="password"
                           value={password.toString()}
                           required
                           className="border border-gray-400 p-2 w-full"
                    />
                </div>
                
                <button className="bg-blue-500 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-full">
                    Submit
                </button>
            </form>
        </div>
    )
}

2. 创建服务端PocketBase工具函数

在项目中创建一个服务端可用的工具函数,用于从Cookies获取令牌并初始化PocketBase实例:

// app/lib/pocketbase-server.ts
import PocketBase from 'pocketbase';
import { cookies } from 'next/headers';

export async function createPocketBaseInstance() {
    const pb = new PocketBase('https://pockettest.lightin.io');
    
    // 从Cookies读取令牌
    const authCookie = cookies().get('pb_auth');
    if (authCookie) {
        pb.authStore.loadFromCookie(`pb_auth=${authCookie.value}`);
        
        // 验证令牌有效性,自动刷新过期令牌
        try {
            if (pb.authStore.isValid) {
                await pb.collection('users').authRefresh();
            }
        } catch (_) {
            // 令牌无效则清空
            pb.authStore.clear();
        }
    }
    
    return pb;
}

3. 在Server Components中使用

现在可以在Server Components里调用这个工具函数,获取已验证的PocketBase实例,进行数据查询:

// app/protected/page.tsx
import { redirect } from 'next/navigation';
import { createPocketBaseInstance } from '../lib/pocketbase-server';

export default async function ProtectedPage() {
    const pb = await createPocketBaseInstance();
    
    // 检查用户是否已认证
    if (!pb.authStore.isValid) {
        // 未认证则重定向到登录页
        return redirect('/login');
    }
    
    // 使用PocketBase查询数据
    const user = pb.authStore.model;
    const records = await pb.collection('your-collection').getList(1, 20);
    
    return (
        <div>
            <h1>欢迎, {user?.email}</h1>
            <ul>
                {records.items.map(item => (
                    <li key={item.id}>{item.title}</li>
                ))}
            </ul>
        </div>
    );
}

4. 处理登出逻辑

登出时需要同时清空客户端的authStore和服务端Cookies:

// app/components/LogoutButton.tsx
'use client';
import { useRouter } from 'next/navigation';
import PocketBase from 'pocketbase';

const pb = new PocketBase('https://pockettest.lightin.io');

export default function LogoutButton() {
    const router = useRouter();
    
    const handleLogout = () => {
        pb.authStore.clear();
        // 清空Cookies
        document.cookie = `pb_auth=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC; HttpOnly; Secure; SameSite=Lax`;
        router.push('/login');
    };
    
    return <button onClick={handleLogout}>登出</button>;
}

关键注意事项

  • 安全性:设置Cookies的HttpOnly和Secure属性,防止XSS攻击,仅在HTTPS环境下传输。
  • 令牌刷新:服务端每次初始化实例时调用authRefresh,确保令牌始终有效。
  • Server Components特性:Server Components中无法直接访问浏览器的window或document,必须通过Cookies传递会话信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 14:45:34