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

Next.js中间件设置Cookie后Supabase Auth自动登出问题

问题:Next.js中间件设置自定义Cookie后,Supabase登录会话立即被删除

问题原因

你的代码存在两个关键问题,导致Supabase的会话Cookie丢失:

  1. Supabase客户端的Cookie处理逻辑错误
    在createServerClient的cookies.set和cookies.remove方法中,你每次都重新创建NextResponse.next()对象并赋值给response,这会清空之前已经设置的所有Cookie(包括Supabase的会话Cookie)。每次创建新的NextResponse对象都会重置Cookie集合,之前的设置全部丢失。

  2. 重定向时未保留已有Cookie
    当用户登录后触发重定向(response = NextResponse.redirect(...))时,你直接用全新的重定向Response替换了原本带有Supabase会话Cookie的Response,导致会话Cookie没有被包含在重定向响应中,浏览器无法存储会话,从而登录后立即失效。

解决方案

步骤1:修复Supabase的Cookie处理逻辑

移除set和remove方法中重新创建NextResponse的代码,直接在初始的response对象上修改Cookie,避免丢失已设置的Cookie。

步骤2:重定向时复制已有Cookie

当需要创建重定向Response时,先复制原Response中的所有Cookie到新的重定向Response中,再添加自定义Cookie或修改逻辑。

修正后的完整代码

import { createServerClient, type CookieOptions } from '@supabase/ssr'
import { type NextRequest, NextResponse } from 'next/server'

export async function middleware(request: NextRequest) {
  // 初始化response,仅创建一次
  let response = NextResponse.next({
    request: {
      headers: request.headers,
    },
  })

  const supabase = createServerClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    {
      cookies: {
        get(name: string) {
          return request.cookies.get(name)?.value
        },
        set(name: string, value: string, options: CookieOptions) {
          // 仅修改request和response的cookies,不重新创建response
          request.cookies.set({
            name,
            value,
            ...options,
          })
          response.cookies.set({
            name,
            value,
            ...options,
          })
        },
        remove(name: string, options: CookieOptions) {
          request.cookies.set({
            name,
            value: '',
            ...options,
          })
          response.cookies.set({
            name,
            value: '',
            ...options,
          })
        },
      },
    }
  )

  const session = await supabase.auth.getUser()
  const path = request.nextUrl.pathname;

  // 处理路由守卫逻辑
  if (!session.data.user && !['/login', '/auth/callback', '/register', '/_next'].includes(path)) {
    // 创建重定向response,并复制原response的所有Cookie
    const redirectResponse = NextResponse.redirect(new URL('/register', request.url));
    response.cookies.getAll().forEach(cookie => {
      redirectResponse.cookies.set(cookie);
    });
    response = redirectResponse;
  } else if (session.data.user && (path === '/login' || path === '/register')) {
    // 同样复制Cookie到重定向响应
    const redirectResponse = NextResponse.redirect(new URL('/', request.url));
    response.cookies.getAll().forEach(cookie => {
      redirectResponse.cookies.set(cookie);
    });
    response = redirectResponse;
  }

  // 安全设置自定义Cookie,不会丢失会话Cookie
  response.cookies.set("test", "test", {
    // 建议添加和Supabase Cookie一致的选项,避免浏览器策略拦截
    sameSite: 'lax',
    path: '/',
    secure: process.env.NODE_ENV === 'production',
  });

  return response
}

额外说明

  • 自定义Cookie建议添加和Supabase会话Cookie一致的选项(如sameSite、path、secure),避免浏览器因Cookie策略拒绝存储。
  • 始终确保所有需要保留的Cookie都被复制到新的Response对象中,无论是重定向还是其他Response修改操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 05:25:39