解决Next.js 13中NextAuth登录302重定向与csrf=true错误
解决NextAuth多路由登录时302重定向404问题
问题概述
在Next.js 13中配置了两个独立的NextAuth路由(管理员/api/auth/admin/[...nextauth]/route.ts和用户/api/auth/user/[...nextauth]/route.ts),调用管理员登录接口时出现302重定向到/api/auth/signin导致404,URL附带csrf=true参数。
核心原因
- 多NextAuth实例未做配置隔离,导致会话存储、路由匹配冲突
- 登录请求端点错误,使用了跳转用的
signin路径而非凭据验证的callback路径 - 请求数据格式不符合CredentialsProvider的默认要求,触发登录失败重定向
- Middleware规则冲突,同时导出默认和自定义逻辑导致路由判断异常
解决方案
1. 为每个NextAuth实例配置隔离参数
修改管理员路由,添加basePath、独立secret和JWT会话策略,避免多实例冲突:
import { NextAuthOptions } from "next-auth"; import NextAuth from "next-auth/next"; import CredentialsProvider from "next-auth/providers/credentials"; const authOption: NextAuthOptions = { secret: process.env.NEXTAUTH_ADMIN_SECRET, // 管理员独立密钥 basePath: "/api/auth/admin", // 指定当前实例的基础路径 session: { strategy: "jwt", // 使用JWT会话,避免共享数据库会话 }, providers: [ CredentialsProvider({ name: "Credentials", credentials: { email: { label: "email", type: "text", placeholder: "jsmith" }, password: { label: "Password", type: "password" } }, async authorize(credentials, req) { // 这里替换为实际的管理员验证逻辑 const user = { id: "1", name: "J Smith", email: "jsmith@example.com" } console.log(credentials?.email); return user ? user : null; } }) ], pages: { signIn: '/auth/admin', error: '/auth/admin/', }, callbacks: { async signIn({ user, account, profile, email, credentials }) { return true; }, } } const handler = NextAuth(authOption); export { handler as GET, handler as POST }
用户路由同理,仅修改以下参数:
secret: process.env.NEXTAUTH_USER_SECRETbasePath: "/api/auth/user"pages.signIn: '/auth/user'
同时在.env文件中添加两个独立密钥:
NEXTAUTH_ADMIN_SECRET=your_admin_unique_secret_key NEXTAUTH_USER_SECRET=your_user_unique_secret_key
2. 修正登录请求端点与数据格式
将登录请求的端点改为凭据验证专用的callback/credentials,并使用form-urlencoded格式(CredentialsProvider默认要求):
const csrf = await fetch('/api/auth/admin/csrf'); const { csrfToken } = await csrf.json(); // 转换formData为表单格式 const formDataParams = new URLSearchParams(); for (const [key, value] of Object.entries(formData)) { formDataParams.append(key, value); } const response = await fetch('/api/auth/admin/callback/credentials', { method: 'POST', headers: { 'X-CSRF-Token': csrfToken, }, body: formDataParams, redirect: 'manual' }); if (response.ok) { // 登录成功后获取会话信息 const sessionRes = await fetch('/api/auth/admin/session'); const session = await sessionRes.json(); console.log('管理员登录成功', session); } else { const errorData = await response.json(); console.error('管理员登录失败', errorData); }
3. 重构Middleware逻辑,避免规则冲突
移除默认的NextAuth middleware导出,整合自定义验证逻辑,指定每个路由对应的Auth实例参数:
import { NextRequest, NextResponse } from "next/server"; import { getToken } from "next-auth/jwt"; export const config = { matcher: ["/admin/:path*", "/user/:path*"] } export async function middleware(request: NextRequest) { // 管理员路由验证 if (request.nextUrl.pathname.startsWith('/admin')) { const token = await getToken({ req: request, secret: process.env.NEXTAUTH_ADMIN_SECRET, basePath: "/api/auth/admin" }); if (!token) { return NextResponse.redirect(new URL('/auth/admin', request.url)); } } // 用户路由验证 if (request.nextUrl.pathname.startsWith('/user')) { const token = await getToken({ req: request, secret: process.env.NEXTAUTH_USER_SECRET, basePath: "/api/auth/user" }); if (!token) { return NextResponse.redirect(new URL('/auth/user', request.url)); } } return NextResponse.next(); }
4. 自定义登录页面表单提交优化
如果使用自定义登录页面(如app/auth/admin/page.tsx),确保表单提交指向正确的端点:
export default function AdminLoginPage() { const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.currentTarget); const csrfRes = await fetch('/api/auth/admin/csrf'); const { csrfToken } = await csrfRes.json(); const response = await fetch('/api/auth/admin/callback/credentials', { method: 'POST', headers: { 'X-CSRF-Token': csrfToken, }, body: formData, redirect: 'follow' }); if (response.ok) { window.location.href = '/admin'; } }; return ( <form onSubmit={handleSubmit}> <input type="email" name="email" required placeholder="管理员邮箱" /> <input type="password" name="password" required placeholder="管理员密码" /> <button type="submit">登录</button> </form> ); }
总结
通过隔离多NextAuth实例的配置参数、修正登录请求的端点与格式、重构Middleware逻辑,即可解决登录时302重定向到错误路径导致的404问题。
内容的提问来源于stack exchange,提问作者jojo
相关产品推荐
相关产品推荐

