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

Next.js App Router中服务端请求后跳转登录页的通用实现

Next.js App Router 通用服务端认证与自动跳转实现

概念性错误排查

先明确几个关键问题,避免踩坑:

  1. 硬编码redirect完全没必要:服务端可以自动获取当前请求路径,不需要手动写死/profile这类路径。
  2. 服务端跳转必须用redirect函数:App Router的服务端组件里不能用客户端的useRouter做跳转,必须用Next.js提供的redirect函数,且要在组件渲染前的顶级await中调用。
  3. 认证逻辑要放在服务端:不能在客户端组件里处理Cookie认证和401跳转,否则会泄露未授权页面的结构,也无法有效拦截未登录请求。

通用实现方案

方案1:封装通用服务端认证函数(适合灵活控制单页逻辑)

写一个可复用的认证函数,在需要认证的页面中直接调用,自动处理401跳转并携带当前路径:

// app/utils/auth.ts
import { redirect } from 'next/navigation';
import { cookies, headers } from 'next/headers';

export async function getUserWithAuth() {
  // 获取服务端Cookie
  const authCookie = cookies().get('auth-token')?.value;

  // 调用后端认证接口
  const res = await fetch('https://你的后端域名/user', {
    headers: {
      Cookie: authCookie ? `auth-token=${authCookie}` : ''
    },
    cache: 'no-store' // 禁用缓存,确保每次请求都验证
  });

  if (res.status === 401) {
    // 获取当前页面的完整URL(包含路径和查询参数)
    const currentUrl = headers().get('x-nextjs-url') || '/';
    // 编码路径,避免特殊字符破坏URL结构
    const encodedRedirect = encodeURIComponent(currentUrl);
    // 跳转到登录页并携带redirect参数
    redirect(`/login?redirect=${encodedRedirect}`);
  }

  if (!res.ok) {
    throw new Error('获取用户数据失败');
  }

  return res.json();
}

在需要认证的页面中直接使用:

// app/profile/page.tsx
import { getUserWithAuth } from '@/app/utils/auth';

export default async function ProfilePage() {
  // 顶级await调用认证函数,自动处理跳转
  const user = await getUserWithAuth();

  return (
    <div>
      <h1>个人中心</h1>
      <p>欢迎你,{user.nickname}</p>
    </div>
  );
}

方案2:用Middleware统一拦截(适合全局批量路由)

如果大部分页面都需要认证,用Next.js中间件可以统一处理,不用每个页面都写代码:

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export async function middleware(request: NextRequest) {
  // 排除不需要认证的路由(登录页、公共页面等)
  const publicPaths = ['/login', '/register', '/public'];
  if (publicPaths.some(path => request.nextUrl.pathname.startsWith(path))) {
    return NextResponse.next();
  }

  // 获取认证Cookie
  const authCookie = request.cookies.get('auth-token')?.value;

  // 无Cookie直接跳转登录
  if (!authCookie) {
    const encodedRedirect = encodeURIComponent(request.nextUrl.href);
    return NextResponse.redirect(new URL(`/login?redirect=${encodedRedirect}`, request.url));
  }

  // 调用后端验证Cookie有效性
  const validateRes = await fetch('https://你的后端域名/validate-token', {
    headers: {
      Cookie: `auth-token=${authCookie}`
    },
    cache: 'no-store'
  });

  // 验证失败跳转登录
  if (validateRes.status === 401) {
    const encodedRedirect = encodeURIComponent(request.nextUrl.href);
    return NextResponse.redirect(new URL(`/login?redirect=${encodedRedirect}`, request.url));
  }

  // 认证通过,放行请求
  return NextResponse.next();
}

// 指定需要拦截的路由(所有需要认证的页面)
export const config = {
  matcher: ['/profile/:path*', '/dashboard/:path*', '/settings/:path*'],
};

注意事项

  • 调用后端接口时要加cache: 'no-store',避免Next.js缓存认证结果,导致用户登出后仍能访问页面。
  • 必须用encodeURIComponent编码redirect参数,防止路径中的?、&等特殊字符破坏URL结构。
  • 中间件中调用后端接口要注意性能,避免频繁请求,可以考虑加入短时间缓存(比如用Redis),但要确保认证状态实时更新。

内容的提问来源于stack exchange,提问作者Georg Windhaber

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 17:57:05