NextAuth自定义登录页凭证认证后无法跳转问题排查
NextAuth v5登录成功后无法跳转的问题排查
环境
- Next.js 15.0.1
- NextAuth 5.0.0-beta
问题描述
我使用NextAuth(v5)在/signin页面搭建了登录表单,用户输入邮箱和密码提交后,登录流程能正常执行,但认证成功后页面无法自动跳转。尝试了教程中提到的在signIn方法里指定redirectTo或设置callbackUrl,均未解决问题。
代码示例
import { AuthError } from 'next-auth' import { Button } from '~/components/ui/button' import { Input } from '~/components/ui/input' import { Label } from '~/components/ui/label' import { signIn } from '~/server/auth' export const SigninForm = async () => { return ( <form action={async (formData) => { 'use server' try { // ① 登录成功,但无跳转 await signIn('credentials', formData) // ② 登录成功,但无跳转 await signIn('credentials', { email: formData.get('email'), password: formData.get('password'), redirectTo: '/dashboard', }) // ③ 登录成功,但无跳转 await signIn('credentials', { email: formData.get('email'), password: formData.get('password'), callbackUrl: '/dashboard', }) } catch (error) { if (error instanceof AuthError) { console.log('error', error) } } }} className='flex flex-col items-center gap-8' > <div className='flex flex-col w-full max-w-sm items-center gap-2'> <div className='grid w-full max-w-sm items-center gap-1.5'> <Label htmlFor='email' className='text-xs'> E-mail </Label> <Input type='email' name='email' id='email' placeholder='example@mail.com' /> </div> <div className='grid w-full max-w-sm items-center gap-1.5'> <Label htmlFor='password' className='text-xs'> Password </Label> <Input type='password' name='password' id='password' /> </div> </div> <Button type='submit' className='grid w-full max-w-sm items-center'> Submit </Button> </form> ) }
问题原因及解决方案
核心原因
NextAuth v5的signIn方法在Server Action中执行成功时,会通过抛出重定向异常来触发页面跳转,但你的代码中try/catch块捕获了所有异常,包括这个用于跳转的重定向异常,导致跳转逻辑被拦截。同时代码中重复调用三次signIn,属于冗余操作,会造成逻辑混乱。
修复步骤
- 移除冗余的
signIn调用:只保留一个正确的调用,使用NextAuth v5推荐的redirectTo参数(callbackUrl是旧版本参数,不建议使用)。 - 调整异常捕获逻辑:仅捕获
AuthError类型的认证错误,其他异常(如重定向异常)重新抛出,让Next.js处理跳转。
修复后的代码
import { AuthError } from 'next-auth' import { Button } from '~/components/ui/button' import { Input } from '~/components/ui/input' import { Label } from '~/components/ui/label' import { signIn } from '~/server/auth' export const SigninForm = async () => { return ( <form action={async (formData) => { 'use server' try { // 仅保留一个正确的登录调用,指定跳转目标 await signIn('credentials', { email: formData.get('email'), password: formData.get('password'), redirectTo: '/dashboard', }) } catch (error) { if (error instanceof AuthError) { console.log('认证失败', error) // 此处可添加前端错误提示逻辑,比如设置状态传递给组件 } else { // 重定向异常重新抛出,让Next.js执行跳转 throw error } } }} className='flex flex-col items-center gap-8' > <div className='flex flex-col w-full max-w-sm items-center gap-2'> <div className='grid w-full max-w-sm items-center gap-1.5'> <Label htmlFor='email' className='text-xs'> E-mail </Label> <Input type='email' name='email' id='email' placeholder='example@mail.com' /> </div> <div className='grid w-full max-w-sm items-center gap-1.5'> <Label htmlFor='password' className='text-xs'> Password </Label> <Input type='password' name='password' id='password' /> </div> </div> <Button type='submit' className='grid w-full max-w-sm items-center'> Submit </Button> </form> ) }
内容的提问来源于stack exchange,提问作者Mikoshiba-Kyu
相关产品推荐
相关产品推荐

