
关于
Supabase Auth 与 Next.js App Router 的专家级集成。
name: nextjs-supabase-auth description: Supabase Auth 与 Next.js App Router 的专业集成 risk: none source: vibeship-spawner-skills (Apache 2.0) date_added: 2026-02-27
Next.js + Supabase Auth
Supabase Auth 与 Next.js App Router 的专业集成
能力
- nextjs-auth
- supabase-auth-nextjs
- auth-middleware
- auth-callback
前置条件
- 所需技能:nextjs-app-router、supabase-backend
模式
Supabase 客户端设置
为不同上下文创建正确配置的 Supabase 客户端
适用场景:在 Next.js 项目中设置认证
// lib/supabase/client.ts(浏览器客户端)
'use client'
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
// lib/supabase/server.ts(服务端客户端)
import { createServerClient } from '@supabase/ssr'
import { cookies } from 'next/headers'
export async function createClient() {
const cookieStore = await cookies()
return createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return cookieStore.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => {
cookieStore.set(name, value, options)
})
},
},
}
)
}
认证中间件
在中间件中保护路由和刷新会话
适用场景:需要路由保护或会话刷新时
// middleware.ts
import { createServerClient } from '@supabase/ssr'
import { NextResponse, type NextRequest } from 'next/server'
export async function middleware(request: NextRequest) {
let response = NextResponse.next({ request })
const supabase = createServerClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
{
cookies: {
getAll() {
return request.cookies.getAll()
},
setAll(cookiesToSet) {
cookiesToSet.forEach(({ name, value, options }) => {
response.cookies.set(name, value, options)
})
},
},
}
)
// 如果过期则刷新会话
const { data: { user } } = await supabase.auth.getUser()
// 保护 dashboard 路由
if (request.nextUrl.pathname.startsWith('/dashboard') && !user) {
return NextResponse.redirect(new URL('/login', request.url))
}
return response
}
export const config = {
matcher: ['/((?!_next/static|_next/image|favicon.ico).*)'],
}
认证回调路由
处理 OAuth 回调并将 code 交换为会话
适用场景:使用 OAuth 提供商(Google、GitHub 等)时
// app/auth/callback/route.ts
import { createClient } from '@/lib/supabase/server'
import { NextResponse } from 'next/server'
export async function GET(request: Request) {
const { searchParams, origin } = new URL(request.url)
const code = searchParams.get('code')
const next = searchParams.get('next') ?? '/'
if (code) {
const supabase = await createClient()
const { error } = await supabase.auth.exchangeCodeForSession(code)
if (!error) {
return NextResponse.redirect(`${origin}${next}`)
}
}
return NextResponse.redirect(`${origin}/auth/error`)
}
Server Action 认证
在 Server Actions 中处理认证操作
适用场景:从 Server Components 进行登录、登出或注册
// app/actions/auth.ts
'use server'
import { createClient } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'
export async function signIn(formData: FormData) {
const supabase = await createClient()
const { error } = await supabase.auth.signInWithPassword({
email: formData.get('email') as string,
password: formData.get('password') as string,
})
if (error) {
return { error: error.message }
}
revalidatePath('/', 'layout')
redirect('/dashboard')
}
export async function signOut() {
const supabase = await createClient()
await supabase.auth.signOut()
revalidatePath('/', 'layout')
redirect('/')
}
在 Server Component 中获取用户
在 Server Components 中访问已认证的用户
适用场景:在服务端渲染用户特定内容
// app/dashboard/page.tsx
import { createClient } from '@/lib/supabase/server'
import { redirect } from 'next/navigation'
export default async function DashboardPage() {
const supabase = await createClient()
const { data: { user } } = await supabase.auth.getUser()
if (!user) {
redirect('/login')
}
return (
<div>
<h1>Welcome, {user.email}</h1>
</div>
)
}
验证检查
使用 getSession() 进行认证检查
严重性:错误
说明:getSession() 不验证 JWT。使用 getUser() 进行安全的认证检查。
修复方式:将安全关键检查中的 getSession() 替换为 getUser()
兼容工具
Claude CodeCursor
标签
后端开发
