Next-Auth自定义登录页中useRouter.push()无法跳转至callbackUrl
问题分析与解决方法
核心问题原因
在Next.js 13 App Router + Next-Auth 4的组合中,当使用redirect: false手动处理登录跳转时,直接调用router.push(callbackUrl)失效,大概率是因为Next-Auth的Session未完成客户端同步,或自定义的callbackUrl未通过Next-Auth的合法性校验。另外你使用的是Next.js的Canary测试版,可能存在路由跳转的临时兼容问题。
针对性解决方案
方案1:使用signIn返回的res.url跳转
Next-Auth在redirect: false模式下,登录成功时会返回经过校验的合法跳转地址res.url,直接用这个地址跳转可避免自定义地址的校验问题:
async function onSubmit(event) { event.preventDefault(); try { setLoading(true); const res = await signIn("credentials", { redirect: false, courseName: course, password: password, callbackUrl }); if (!res?.error) { setError(""); // 改用res.url而非自定义的callbackUrl if (res.url) { console.log(`redirecting to ${res.url}`); router.push(res.url); } } else { setError("falsches Passwort"); } setLoading(false); } catch (error) { setLoading(false); setError(error); } }
方案2:等待Session同步后再跳转
利用Next-Auth的useSession钩子监听登录状态,确保客户端Session更新完成后再执行跳转:
- 先导入
useSession:
import { signIn, useSession } from "next-auth/react";
- 在组件中添加监听逻辑:
export default function LoginPage() { const router = useRouter(); const callbackUrl = useSearchParams().get("callbackUrl") || "/"; const course = callbackUrl.split("/").pop(); let [loading, setLoading] = useState(false); let [password, setPassword] = useState(""); const [error, setError] = useState(""); const { data: session } = useSession(); // 监听Session变化,登录成功后自动跳转 useEffect(() => { if (session && !loading) { router.push(callbackUrl); } }, [session, router, callbackUrl, loading]); async function onSubmit(event) { event.preventDefault(); try { setLoading(true); const res = await signIn("credentials", { redirect: false, courseName: course, password: password, callbackUrl }); if (res?.error) { setError("falsches Passwort"); } else { setError(""); } setLoading(false); } catch (error) { setLoading(false); setError(error); } } // 其余代码保持不变... }
方案3:降级Next.js至稳定版
你当前使用的13.4.8-canary.2是测试版,可能存在路由跳转的未知bug,建议降级到同系列的稳定版本(如13.4.19):
npm install next@13.4.19
额外注意事项
- 确保
next-auth.config.js中配置了正确的NEXTAUTH_URL,且callbackUrl属于允许的跳转域名范围; - 给登录页面添加动态渲染标识,避免页面被缓存导致状态异常:
"use client"; // 添加此行确保页面每次都重新渲染 export const dynamic = "force-dynamic"; // 其余代码...
内容的提问来源于stack exchange,提问作者kzi
相关产品推荐
相关产品推荐

