服务端阅读 06月2日 23:13
Next.js 认证怎么做?NextAuth.js 配置 OAuth 和凭证登录实战
Next.js 认证最主流的方案是 NextAuth.js(v5 改名 Auth.js)。它处理了 OAuth、JWT、Session 管理等所有细节,30 分钟就能搭好 Google/GitHub 登录。最快上手:NextAuth.jsnpm install next-auth@beta// app/api/auth/[...nextauth]/route.tsimport NextAuth from 'next-auth';import GitHub from 'next-auth/providers/github';export const { handlers, auth, signIn, signOut } = NextAuth({ providers: [ GitHub({ clientId: process.env.GITHUB_ID, clientSecret: process.env.GITHUB_SECRET, }), ], pages: { signIn: '/login', // 自定义登录页 },});export const { GET, POST } = handlers;// middleware.ts — 保护路由export { auth as middleware } from './app/api/auth/[...nextauth]/route';export const config = { matcher: ['/dashboard/:path*'],};三步:配置 provider → 创建 API 路由 → 加中间件保护。用户访问 /dashboard 时如果没有登录,自动跳转到 /login。在 Server Component 里获取 Sessionimport { auth } from './app/api/auth/[...nextauth]/route';export default async function Dashboard() { const session = await auth(); if (!session) { redirect('/login'); } return <h1>欢迎, {session.user.name}</h1>;}auth() 在服务端获取 session,不需要客户端 JavaScript。这是 RSC 的优势——认证逻辑完全在服务端,客户端零开销。在 Client Component 里获取 Session'use client'import { useSession } from 'next-auth/react';export default function Profile() { const { data: session, status } = useSession(); if (status === 'loading') return <p>加载中...</p>; if (!session) return <p>请先登录</p>; return <p>{session.user.name}</p>;}useSession 通过轮询 /api/auth/session 获取 session。更高效的方式是用 SessionProvider:// app/providers.tsx'use client'import { SessionProvider } from 'next-auth/react';export function Providers({ children }) { return <SessionProvider>{children}</SessionProvider>;}包在 layout 里后,useSession 不再轮询,而是通过 Context 共享 session 数据。自定义登录页默认登录页太简陋。自定义页面:// app/login/page.tsximport { signIn } from '@/auth';export default function LoginPage() { return ( <form action={async () => { 'use server' await signIn('github'); }}> <button type="submit">用 GitHub 登录</button> </form> );}用 Server Action 触发 signIn,比客户端 signIn() 更简洁。凭证登录(用户名密码)OAuth 不够时,加 Credentials provider:import Credentials from 'next-auth/providers/credentials';import bcrypt from 'bcryptjs';export const { handlers, auth } = NextAuth({ providers: [ Credentials({ credentials: { email: { label: 'Email', type: 'email' }, password: { label: 'Password', type: 'password' }, }, async authorize(credentials) { const user = await db.user.findUnique({ where: { email: credentials.email }, }); if (!user) return null; const valid = await bcrypt.compare(credentials.password, user.passwordHash); if (!valid) return null; return { id: user.id, name: user.name, email: user.email }; }, }), ],});authorize 返回 null 表示认证失败,返回 user 对象表示成功。密码必须用 bcrypt 哈希,不要存明文。常见问题Session 过期后页面不刷新:用 SessionProvider 的 refetchInterval 定时刷新:<SessionProvider refetchInterval={300}> 每 5 分钟检查一次。OAuth 回调 404:确保回调 URL 在 OAuth provider 里配置正确。GitHub 在 Settings > Developer > OAuth Apps 里配。部署后 Cookie 不工作:NEXTAUTH_URL 环境变量必须设为生产域名。Vercel 部署时自动设置,其他平台需要手动配。