Next.js + Next-auth v5登录成功后重定向失败问题求助
问题分析与解决方案
在tRPC端点中直接调用signIn并依赖redirectTo参数实现重定向的方式不可行,原因是:tRPC mutation属于API请求,服务端抛出的NEXT_REDIRECT错误会被封装为API响应返回给前端,浏览器不会自动执行服务端的重定向指令——这种重定向逻辑仅在页面组件(如RSC或客户端页面)中抛出时才会生效。
以下是具体的修复方案:
1. 修改tRPC登录端点逻辑
将signIn的redirect参数设置为false,让它返回登录结果而非抛出重定向错误,再由前端手动处理跳转:
loginProcedure: publicProcedure.input(LoginSchema).mutation(async (opts) => { const { input } = opts; const validatedFields = LoginSchema.safeParse(input); if (!validatedFields.success) { throw new TRPCError({ code: "PARSE_ERROR", message: "Invalid fields" }); } const { email, password } = validatedFields.data; // 关键:禁用自动重定向,获取登录结果对象 const signInResult = await signIn("credentials", { email, password, redirectTo: DEFAULT_LOGIN_REDIRECT, redirect: false, }); // 处理登录错误 if (signInResult?.error) { if (signInResult.error === "CredentialsSignin") { throw new TRPCError({ code: "UNAUTHORIZED", message: "Invalid credentials", }); } throw new TRPCError({ code: "UNAUTHORIZED", message: "Something went wrong", }); } // 返回成功信息与跳转目标,交给前端处理 return { success: true, redirectTo: DEFAULT_LOGIN_REDIRECT }; }),
2. 前端手动处理重定向
在调用tRPC登录接口的组件中,通过useMutation的onSuccess钩子执行跳转:
import { useRouter } from "next/navigation"; import { trpc } from "@/trpc/client"; export default function LoginForm() { const router = useRouter(); const { mutate, isLoading } = trpc.auth.login.useMutation({ onSuccess: (data) => { // 使用Next.js路由跳转(推荐) router.push(data.redirectTo); // 或用原生方式:window.location.href = data.redirectTo; }, onError: (error) => { // 展示错误提示,比如toast console.error(error.message); }, }); // 表单提交逻辑 const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(e.target as HTMLFormElement); mutate({ email: formData.get("email") as string, password: formData.get("password") as string, }); }; return ( <form onSubmit={handleSubmit}> {/* 表单内容 */} <button type="submit" disabled={isLoading}>登录</button> </form> ); }
3. 验证Middleware配置
确保DEFAULT_LOGIN_REDIRECT对应的路径不会被Middleware拦截:
- 该路径不应出现在
authRoutes数组中(否则已登录用户访问会被循环重定向) - 如果路径不属于
publicRoutes,Middleware中!isLoggedIn && !isPublicRoute的逻辑会拦截未登录用户,这符合预期,但已登录用户可以正常访问
内容的提问来源于stack exchange,提问作者Carlos
相关产品推荐
相关产品推荐

