如何在Next.js中创建可复用的受保护路由
Next.js + Supabase 实现复用的受保护路由方案
根据你当前的场景,下面针对Next.js的两种路由系统(Pages Router、App Router)分别提供符合DRY原则的惯用实现方案:
Pages Router 方案
1. 封装可复用的认证函数
把身份验证逻辑抽成独立工具函数,在每个受保护页面的getServerSideProps中调用,避免重复代码:
首先创建工具函数文件(比如utils/withAuth.js):
import supabase from '../path-to-your-supabase-client'; // 替换为你的Supabase客户端路径 export async function requireAuth(req) { const { user } = await supabase.auth.api.getUserByCookie(req); if (!user) { return { redirect: { destination: '/signin', permanent: false } }; } return { props: { user } }; }
然后在受保护页面中使用:
import { requireAuth } from '../utils/withAuth'; function ProtectedPage({ user }) { return <div>欢迎访问受保护页面,{user.email}</div>; } export async function getServerSideProps({ req }) { const authResult = await requireAuth(req); // 如果需要重定向,直接返回结果 if (authResult.redirect) return authResult; // 这里可添加当前页面专属的服务器端逻辑(比如获取业务数据) const pageData = { /* 页面专属数据 */ }; return { props: { ...authResult.props, ...pageData } }; } export default ProtectedPage;
2. 使用高阶组件(HOC)包装页面
如果希望直接给页面组件添加保护逻辑,无需手动编写getServerSideProps,可以用高阶组件封装:
创建utils/withProtectedRoute.js:
import supabase from '../path-to-your-supabase-client'; export function withProtectedRoute(PageComponent) { const WrappedPage = (props) => <PageComponent {...props} />; // 注入统一的认证逻辑到页面的getServerSideProps WrappedPage.getServerSideProps = async ({ req }) => { const { user } = await supabase.auth.api.getUserByCookie(req); if (!user) { return { redirect: { destination: '/signin', permanent: false } }; } // 如果原页面有自己的getServerSideProps,执行并合并props const pageProps = PageComponent.getServerSideProps ? await PageComponent.getServerSideProps({ req }) : { props: {} }; return { props: { ...pageProps.props, user } }; }; return WrappedPage; }
在页面组件中使用:
import { withProtectedRoute } from '../utils/withProtectedRoute'; function Dashboard({ user }) { return <div>仪表盘 - 欢迎你,{user.email}</div>; } // 可选:页面自己的getServerSideProps逻辑 // Dashboard.getServerSideProps = async () => { // return { props: { /* 页面数据 */ } }; // }; // 用HOC包装页面,自动添加保护逻辑 export default withProtectedRoute(Dashboard);
App Router 方案(Next.js 13+)
如果使用App Router,推荐用Middleware实现全局路由保护,无需在每个页面编写逻辑:
创建项目根目录下的middleware.js:
import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs'; import { NextResponse } from 'next/server'; export async function middleware(req) { const res = NextResponse.next(); const supabase = createMiddlewareClient({ req, res }); // 获取当前用户 const { data: { user } } = await supabase.auth.getUser(); // 定义需要保护的路由规则 const isProtectedRoute = req.nextUrl.pathname.startsWith('/dashboard') || req.nextUrl.pathname.startsWith('/profile'); // 未登录且访问受保护路由,重定向到登录页并保存原路径 if (isProtectedRoute && !user) { const redirectUrl = new URL('/signin', req.url); redirectUrl.searchParams.set('redirectTo', req.nextUrl.pathname); return NextResponse.redirect(redirectUrl); } return res; } // 指定Middleware生效的路由范围 export const config = { matcher: ['/dashboard/:path*', '/profile/:path*'] };
之后在受保护页面中,可直接获取用户信息:
import { createServerComponentClient } from '@supabase/auth-helpers-nextjs'; import { cookies } from 'next/headers'; async function DashboardPage() { const supabase = createServerComponentClient({ cookies }); const { data: { user } } = await supabase.auth.getUser(); return <div>仪表盘 - 你好,{user.email}</div>; } export default DashboardPage;
内容的提问来源于stack exchange,提问作者Neil Girardi
相关产品推荐
相关产品推荐

