You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 10:35:41