Next.js中间件设置Cookie后Supabase Auth自动登出问题
问题原因
你的代码存在两个关键问题,导致Supabase的会话Cookie丢失:
Supabase客户端的Cookie处理逻辑错误
在createServerClient的cookies.set和cookies.remove方法中,你每次都重新创建NextResponse.next()对象并赋值给response,这会清空之前已经设置的所有Cookie(包括Supabase的会话Cookie)。每次创建新的NextResponse对象都会重置Cookie集合,之前的设置全部丢失。重定向时未保留已有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
相关产品推荐
相关产品推荐

