我正在使用 Supabase 创建一个 Nextjs 项目。我正在通过 Google OAuth 提供商使用 Supabase 客户端对用户进行身份验证。我遵循了此 github 存储库的确切代码:https://github.com/SamuelSackey/nextjs-supabase-example
整个认证过程运行良好。但是当用户登录一段时间后,一段时间后,页面无法加载,我收到错误:
Error: Cookies can only be modified in a Server Action or Route Handler. Read more:
https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-
options
at Object.set (./src/lib/supabase/server-clients.ts:27:73)
at Array.map (<anonymous>)
这是我的服务器客户端.ts
import { type CookieOptions, createServerClient } from '@supabase/ssr';
import { getCookie, setCookie } from 'cookies-next';
import { cookies } from 'next/headers';
import { type NextRequest, type NextResponse } from 'next/server';
import { SUPABASE_ANON_KEY, SUPABASE_URL } from '@/constant/env';
// server component can only get cookies and not set them, hence the "component" check
export function createSupabaseServerClient(component = false) {
return createServerClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
cookies: {
get(name: string) {
return cookies().get(name)?.value;
},
set(name: string, value: string, options: CookieOptions) {
if (component) return;
cookies().set(name, value, options);
},
remove(name: string, options: CookieOptions) {
if (component) return;
cookies().set(name, '', options);
},
},
});
}
export function createSupabaseServerComponentClient() {
return createSupabaseServerClient(true);
}
export function createSupabaseReqResClient(
req: NextRequest,
res: NextResponse
) {
cookies().getAll(); // Keep cookies in the JS execution context for Next.js build
return createServerClient(SUPABASE_URL, SUPABASE_ANON_KEY, {
cookies: {
get(name: string) {
return getCookie(name, { req, res });
},
set(name: string, value: string, options: CookieOptions) {
setCookie(name, value, { req, res, ...options });
},
remove(name: string, options: CookieOptions) {
setCookie(name, '', { req, res, ...options });
},
},
});
}
中间件.ts
import { type NextRequest, NextResponse } from 'next/server';
import { createSupabaseReqResClient } from '@/lib/supabase/server-clients';
export async function middleware(request: NextRequest) {
const response = NextResponse.next({
request: {
headers: request.headers,
},
});
const supabase = createSupabaseReqResClient(request, response);
const {
data: { session },
} = await supabase.auth.getSession();
const user = session?.user;
if (!user && request.nextUrl.pathname.startsWith('/my-profile')) {
return NextResponse.redirect(new URL('/', request.url));
}
return response;
}
export const config = {
matcher: ['/my-profile'],
};
api/auth/callback/route.ts
import { NextResponse } from 'next/server';
import { createSupabaseServerClient } from '@/lib/supabase/server-clients';
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url);
const code = searchParams.get('code');
// if "next" is in param, use it in the redirect URL
// const next = searchParams.get('next') ?? '/';
if (code) {
const supabase = createSupabaseServerClient();
const { error } = await supabase.auth.exchangeCodeForSession(code);
if (!error) {
return NextResponse.redirect(origin);
}
}
// TODO:
// return the user to an error page with instructions
return NextResponse.redirect(`${origin}/auth/auth-error`);
}
为什么我仅在用户登录一段时间后而不是在初始身份验证过程中出现此错误?如何解决这个错误?
已在 github 存储库中打开拉取请求来解决此问题。