📖 核心概念
- 认证vs授权vs身份
- NextAuth.js v5架构
- OAuth社交登录
- JWT与Session策略
- 保护路由与API
- 多因素认证(MFA)
💻 代码实现
NextAuth配置
✅ typescript
// auth.ts
import NextAuth from 'next-auth';
import GitHub from 'next-auth/providers/github';
import Google from 'next-auth/providers/google';
import Credentials from 'next-auth/providers/credentials';
import { PrismaAdapter } from '@auth/prisma-adapter';
import { prisma } from '@/lib/prisma';
export const { handlers, auth, signIn, signOut } = NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
GitHub({
clientId: process.env.GITHUB_ID,
clientSecret: process.env.GITHUB_SECRET,
}),
Google({
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
}),
Credentials({
name: 'credentials',
credentials: {
email: { label: '邮箱', type: 'email' },
password: { label: '密码', type: 'password' },
},
async authorize(credentials) {
const validated = loginSchema.safeParse(credentials);
if (!validated.success) return null;
const user = await prisma.user.findUnique({
where: { email: validated.data.email },
});
if (!user?.password) return null;
const isValid = await bcrypt.compare(validated.data.password, user.password);
if (!isValid) return null;
return { id: user.id, email: user.email, name: user.name };
},
}),
],
session: { strategy: 'jwt', maxAge: 7 * 24 * 60 * 60 },
pages: {
signIn: '/login',
error: '/auth/error',
},
callbacks: {
async jwt({ token, user }) {
if (user) {
token.id = user.id;
token.role = (user as any).role;
}
return token;
},
async session({ session, token }) {
if (session.user) {
session.user.id = token.id as string;
(session.user as any).role = token.role;
}
return session;
},
},
});
// app/api/auth/[...nextauth]/route.ts
export const { GET, POST } = handlers;
// 中间件保护路由
// middleware.ts
export { auth as middleware } from '@/auth';
export const config = {
matcher: ['/dashboard/:path*', '/api/protected/:path*'],
};
认证组件与API保护
✅ tsx
// 组件中获取用户信息
import { auth } from '@/auth';
// Server Component
export default async function DashboardPage() {
const session = await auth();
if (!session) {
redirect('/login');
}
return (
<div>
<h1>欢迎, {session.user.name}</h1>
<img src={session.user.image} alt="avatar" />
</div>
);
}
// Client Component
'use client';
import { useSession } from 'next-auth/react';
function UserMenu() {
const { data: session, status } = useSession();
if (status === 'loading') return <Skeleton />;
if (status === 'unauthenticated') return <LoginButton />;
return (
<div className="user-menu">
<img src={session.user.image} alt="" />
<span>{session.user.name}</span>
<button onClick={() => signOut()}>退出</button>
</div>
);
}
// 保护API路由
import { auth } from '@/auth';
export async function POST(request: Request) {
const session = await auth();
if (!session) {
return Response.json({ error: '未授权' }, { status: 401 });
}
// 只允许管理员
if ((session.user as any).role !== 'ADMIN') {
return Response.json({ error: '权限不足' }, { status: 403 });
}
const body = await request.json();
// 处理请求...
}
// 注册页面
'use client';
import { useState } from 'react';
import { signIn } from 'next-auth/react';
function RegisterForm() {
const [loading, setLoading] = useState(false);
const handleSubmit = async (e: FormEvent<HTMLFormElement>) => {
e.preventDefault();
setLoading(true);
const formData = new FormData(e.currentTarget);
// 1. 创建账号
const res = await fetch('/api/auth/register', {
method: 'POST',
body: JSON.stringify({
name: formData.get('name'),
email: formData.get('email'),
password: formData.get('password'),
}),
});
if (res.ok) {
// 2. 自动登录
await signIn('credentials', {
email: formData.get('email'),
password: formData.get('password'),
callbackUrl: '/dashboard',
});
}
setLoading(false);
};
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="姓名" required />
<input name="email" type="email" placeholder="邮箱" required />
<input name="password" type="password" placeholder="密码" required />
<button type="submit" disabled={loading}>注册</button>
<div className="divider">或</div>
<button type="button" onClick={() => signIn('github')}>
GitHub 登录
</button>
<button type="button" onClick={() => signIn('google')}>
Google 登录
</button>
</form>
);
}
🎯 练习任务
- 1 配置NextAuth支持GitHub和Google社交登录
- 2 实现邮箱密码注册与登录
- 3 保护API路由,只允许认证用户访问
- 4 实现基于角色的权限控制(RBAC)
🏆 成就解锁
认证安全专家 — 掌握NextAuth身份认证,构建安全的用户系统