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

Next.js+Supabase认证与会话处理问题:无法获取受限数据

问题分析与解决方案

核心问题

你当前的实现无法获取受限行数据,本质原因是Server Component中使用的Supabase客户端没有携带用户会话Cookie:

  • 全局的supabase-client.ts用createClient创建的客户端,不会自动读取Next.js的Cookie会话信息
  • Supabase的RLS(行级安全)策略要求用户认证后才能访问数据,无会话的请求会被拦截,返回空数据

分步修正方案

1. 修正Server Component的Supabase客户端创建

在ingresos/page.tsx中,使用Supabase Auth Helpers提供的createServerComponentClient,它会自动处理Cookie会话传递:

import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { Database } from '@/types/supabase'

export const dynamic = 'force-dynamic'

export default async function obtenerIngresos() {
  // 创建携带Cookie的Server Component专属客户端
  const supabase = createServerComponentClient<Database>({ cookies })

  // 先验证用户会话是否有效
  const { data: { user } } = await supabase.auth.getUser()
  if (!user) {
    return <div className="p-4">请先登录后查看数据</div>
  }

  const { data, error } = await supabase.from("ingresos").select("*");

  // 调试:打印错误信息快速定位问题
  if (error) {
    console.error('获取收入数据失败:', error)
    return <div className="p-4 text-red-500">加载出错:{error.message}</div>
  }

  return (
    <div className="flex flex-col">
        <div className="overflow-x-auto sm:-mx-6 lg:-mx-8">
          <div className="inline-block min-w-full py-2 sm:px-6 lg:px-8">
            <div className="overflow-hidden">
              <table className="min-w-full text-center text-sm font-light">
                <thead className="border-b bg-neutral-800 font-medium text-white dark:border-neutral-500 dark:bg-neutral-900">
                  <tr>
                    <th scope="col" className=" px-6 py-4">#</th>
                    <th scope="col" className=" px-6 py-4">Fuente</th>
                    <th scope="col" className=" px-6 py-4">Cantidad</th>
                    <th scope="col" className=" px-6 py-4">Fecha</th>
                  </tr>
                </thead>
                <tbody>
                  {data?.map((item, index) => (
                    <tr key={index} className="border-b dark:border-neutral-500">
                      <td className="whitespace-nowrap px-6 py-4 font-medium">{index + 1}</td>
                      <td className="whitespace-nowrap px-6 py-4">{item.fuente}</td>
                      <td className="whitespace-nowrap px-6 py-4">{item.cantidad}</td>
                      <td className="whitespace-nowrap px-6 py-4">{item.timestamp_with_time_zone}</td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        </div>
      </div>
  );
}

2. 拆分全局Supabase客户端(区分客户端/服务器端)

修改lib/supabase-client.ts,让它专门服务于客户端组件,自动管理浏览器Cookie:

import { createBrowserClient } from '@supabase/auth-helpers-nextjs'
import { Database } from '../types/supabase'

// 客户端组件专用Supabase客户端
export const supabase = createBrowserClient<Database>(
  process.env.NEXT_PUBLIC_SUPABASE_URL!,
  process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)

如果需要在Route Handler中使用,单独创建lib/supabase-server.ts:

import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs'
import { cookies } from 'next/headers'
import { Database } from '../types/supabase'

export const createSupabaseServerClient = () =>
  createRouteHandlerClient<Database>({ cookies })

3. 确保RLS策略配置正确

检查ingresos表的RLS策略,确保允许认证用户访问数据。例如:

-- 假设表中有user_id字段关联用户ID
CREATE POLICY "认证用户可查看自己的收入" ON public.ingresos
FOR SELECT USING (auth.uid() = user_id);

CREATE POLICY "认证用户可添加收入" ON public.ingresos
FOR INSERT WITH CHECK (auth.uid() = user_id);

4. 类型注入的正确用法

  • 确保types/supabase.ts是通过Supabase CLI生成的,与你的数据库结构完全同步:
    npx supabase gen types typescript --project-id 你的项目ID --schema public > types/supabase.ts
    
  • 在创建任何Supabase客户端时,传入<Database>泛型,即可获得完整的类型提示:
    createServerComponentClient<Database>({ cookies })
    

会话认证与Cookie管理规范

  • Server Component/Route Handler:使用createServerComponentClient/createRouteHandlerClient,传入{ cookies }参数自动读取会话
  • 客户端组件:使用createBrowserClient,自动管理浏览器Cookie会话
  • Middleware:配置路由保护,确保未登录用户无法访问需要认证的页面(示例):
    import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'
    import { NextResponse } from 'next/server'
    import type { NextRequest } from 'next/server'
    
    export async function middleware(req: NextRequest) {
      const res = NextResponse.next()
      const supabase = createMiddlewareClient({ req, res })
    
      const { data: { user } } = await supabase.auth.getUser()
    
      if (!user && req.nextUrl.pathname !== '/login') {
        return NextResponse.redirect(new URL('/login', req.url))
      }
    
      return res
    }
    
    export const config = {
      matcher: ['/ingresos/:path*'],
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 00:54:58