如何在NextJS13+NextAuth+t3栈中实现无会话用户重定向?
针对T3栈未登录重定向的正确实现方案
你遇到的NEXT_REDIRECT错误,是因为直接在客户端组件中调用了Next.js App Router的服务端专属redirect函数——useSession属于客户端钩子,调用它的组件会被标记为客户端组件,而服务端函数不能在客户端环境中执行。
以下是基于T3初始项目的几种可行方案:
方案1:App Router服务端组件实现(推荐)
将页面改为纯服务端组件,在服务端直接获取Session并处理重定向,避免客户端渲染闪烁:
// app/protected/page.tsx import { getServerSession } from "next-auth/next"; import { authOptions } from "@/server/auth"; import { redirect } from "next/navigation"; export default async function ProtectedPage() { const session = await getServerSession(authOptions); if (!session) { redirect("/auth/signin"); // 可替换为首页路径 } return <div>Test</div>; }
注意:该组件不能包含任何客户端钩子(如useSession),如果需要交互逻辑,嵌套客户端组件即可。
方案2:App Router客户端组件实现
若必须使用客户端组件,改用useRouter配合useEffect实现重定向:
// app/protected/page.tsx "use client"; import { useSession } from "next-auth/react"; import { useRouter } from "next/navigation"; import { useEffect } from "react"; export default function ProtectedPage() { const { data: session, status } = useSession(); const router = useRouter(); useEffect(() => { // 等待Session状态加载完成后再判断,避免初始null导致误重定向 if (status === "unauthenticated") { router.push("/auth/signin"); } }, [status, router]); // 加载状态时展示过渡组件 if (status === "loading") { return <div>加载中...</div>; } // 未登录时不渲染页面内容 if (!session) { return null; } return <div>Test</div>; }
方案3:Pages Router项目实现
如果你的T3项目使用旧版Pages Router,在页面的getServerSideProps中处理服务端重定向:
// pages/protected.tsx import { GetServerSideProps, NextPage } from "next"; import { getServerSession } from "next-auth/next"; import { authOptions } from "../server/auth"; import { useSession } from "next-auth/react"; const ProtectedPage: NextPage = () => { const { data: session } = useSession(); return <div>Test</div>; }; export const getServerSideProps: GetServerSideProps = async (context) => { const session = await getServerSession(context.req, context.res, authOptions); if (!session) { return { redirect: { destination: "/auth/signin", permanent: false, }, }; } return { props: {} }; }; export default ProtectedPage;
批量路由保护:NextAuth Middleware
如果需要保护多个路由,推荐使用NextAuth Middleware实现全局拦截,无需每个页面单独编写逻辑:
// middleware.ts import { withAuth } from "next-auth/middleware"; export default withAuth({ pages: { signIn: "/auth/signin", // 未登录时重定向的目标页 }, }); // 配置需要保护的路由规则 export const config = { matcher: ["/protected/:path*", "/dashboard/:path*"], // 匹配所有需要拦截的路由 };
内容的提问来源于stack exchange,提问作者avenmia
相关产品推荐
相关产品推荐

