前端开发
在 Next.js 15+ App Router 中用…
当需要在 Next.js 15+ App Router 项目中搭建登录、受保护路由、会话管理与基于角色的访问控制时使用。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 49/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 85/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 60/100 ×0.15
适用场景
在 Next.js 15+ App Ro通用
解决思路
- 安装依赖:运行 `npm install next-auth@beta` 安装适配 App Router 的 Auth.js v5。
- 配置环境变量:在 `.env.local` 中设置 `AUTH_SECRET`、`AUTH_URL`,以及各 OAuth 提供商的 `GITHUB_ID`/`GITHUB_SECRET`、`GOOGLE_CLIENT_ID`/`GOOGLE_CLIENT_SECRET`;用 `openssl rand -base64 32` 生成 `AUTH_SECRET`。
- 创建认证配置:在项目根目录新建 `auth.ts`,用 `NextAuth({...})` 配置 providers 与 callbacks,并导出 `handlers: { GET, POST }`、`auth`、`signIn`、`signOut`;在 `jwt` callback 中把 `user.id` 写入 `token.id`,在 `session` callback 中把 `token.id` 写回 `session.user.id`,并通过 `pages` 指定 `signIn: "/login"`、`error: "/error"`。
- 创建 API 路由处理器:新建 `app/api/auth/[...nextauth]/route.ts`,内容为 `export { GET, POST } from "@/auth";`。
- 添加中间件保护路由:在根目录新建 `middleware.ts`,用 `export default auth((req) => {...})` 判断 `req.auth` 是否登录;对 `/api/auth` 直接放行,未登录访问 `/dashboard` 等受保护路由时重定向到 `/login`,已登录访问 `/login` 时重定向到 `/dashboard`;并配置 `config.matcher` 排除 `_next/static`、`_next/image`、`favicon.ico`、`*.png` 等静态资源。
- 在 Server Components 中读取会话:调用 `const session = await auth()`,若无 `session` 则 `redirect("/login")`,否则用 `session.user.name` 等渲染页面。
- 保护 Server Actions:在 `"use server"` 函数中先 `const session = await auth()`,若 `!session?.user` 则 `throw new Error("Unauthorized")`,通过后再执行数据库写入等变更操作,并使用 `session.user.id` 关联数据。
- 处理登录:在 `app/login/page.tsx` 中定义 server action,调用 `signIn("credentials", { email, password, redirect: false })`,若返回 `result?.error` 则返回错误信息,否则 `redirect("/dashboard")`;表单用 `<form action={handleLogin}>` 提交。
- 处理登出:在客户端组件中 `"use client"` 下从 `next-auth/react` 导入 `signOut`,用 `<button onClick={() => signOut()}>Sign Out</button>` 触发登出。
- 实现基于角色的访问控制:在 Server Component 中读取 `session`,若 `session?.user?.role !== "admin"` 则调用 `unauthorized()`,否则渲染管理页面。
- 扩展 TypeScript 类型:新建 `types/next-auth.d.ts`,通过 `declare module "next-auth"` 扩展 `Session.user`(加入 `id`、`role`)和 `User`,通过 `declare module "next-auth/jwt"` 扩展 `JWT`(加入 `id`、`role`),实现类型安全的会话。
- 遵循最佳实践:默认使用 Server Components 直接读取会话,仅在需要响应式会话更新时用 `useSession()`;用 React 的 `cache()` 缓存同一渲染中的会话查询;中间件只做乐观检查,Server Actions 中必须重新验证;把 Server Actions 当作 API 端点对待,变更前必须认证;所有凭证走环境变量,绝不硬编码;返回合适的 HTTP 状态码;用 TypeScript 类型扩展自定义字段;把认证逻辑抽到独立的 DAL;在单元测试中 mock `auth()` 函数。
- 规避常见错误:不要在 Server Component 中调用 `cookies().set()`(不会生效),应改用 Server Action;不要在 Middleware 中执行数据库查询(Edge runtime 不支持 Node.js API),只能使用 `req.auth` 等 Edge 兼容 API。
- 注意安全事项:Server Actions 中必须再次验证认证,仅靠中间件不够;未认证用 `unauthorized()`,其他情况用 `redirect()`;敏感 token 存 `httpOnly` cookie;处理前校验所有用户输入;生产环境使用 HTTPS;设置合适的 cookie `sameSite` 属性。
适用边界 · 注意事项
- 项目不是 Next.js 15+ App Router(如 Pages Router 或更早版本),本技能的模式不适用。
- 需要在不支持 Edge runtime 的环境中运行 Middleware,或需要在 Middleware 中直接访问数据库驱动。
- 不使用 Auth.js 5 / NextAuth.js,而采用其他认证方案(如 Clerk、Supabase Auth、自研 JWT 等)。