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

Next.js v15+Auth.js v5:客户端组件页面如何校验用户登录?

客户端组件页面的登录校验方案(Next.js 15 + Auth.js v5)

问题分析

你当前的代码存在几个关键问题:

  1. 客户端组件中不能调用getServerSession,这个方法仅适用于服务器组件或API路由
  2. loginRequiredClient的写法有误:useSession返回的是包含data(会话信息)和status(状态:loading/authenticated/unauthenticated)的对象,不是直接的session;且hook不能在async函数中直接await调用
  3. 客户端页面的登录校验逻辑不完整,未处理会话加载状态

推荐解决方案:服务器端路由组拦截 + 客户端状态处理

步骤1:给私有路由组添加服务器端Layout

在app/(private)/layout.tsx中添加全局登录校验,确保整个私有路由组的页面都被服务器端拦截:

import { authConfig } from "@/app/lib/auth";
import { loginIsRequiredServer } from "@/app/lib/loginIsRequiredServer";
import type { ReactNode } from "react";

export default async function PrivateLayout({ children }: { children: ReactNode }) {
  // 服务器端校验登录,未登录则重定向到首页
  await loginIsRequiredServer();
  return <>{children}</>;
}

步骤2:修改客户端页面的登录状态处理

更新app/(private)/customers/page.tsx,正确使用客户端会话钩子:

"use client";
import { useSession } from "next-auth/react";
import useSWR from "swr";

// 定义客户类型(如果没有全局声明的话)
interface CustomerI {
  customer_id: string;
  customer_name: string;
}

export default function CustomersPage() {
  // 获取客户端会话状态
  const { data: session, status } = useSession();

  // 处理会话加载中状态
  if (status === "loading") {
    return (
      <div>
        <div className="loading"></div>
        <span>加载中...</span>
      </div>
    );
  }

  // 兜底处理:服务器端已拦截,这里仅做客户端状态兼容
  if (!session) {
    return <div>请先登录</div>;
  }

  // 获取客户数据
  const { data: customersData, error: customersError, isLoading: customersIsLoading } = useSWR("/customers/api-customers/api-get-customers/");
  
  if (customersError) return <div className="error_smal"><span>加载失败</span></div>;
  if (customersIsLoading) return (
    <div>
      <div className="loading"></div>
      <span>加载客户数据中...</span>
    </div>
  );

  return (
    <>
      <h1>客户列表</h1>
      <ul>
        {customersData?.data.map((customer: CustomerI) => (
          <li className="list-none" key={customer.customer_id}>
            <p>{customer.customer_name}</p>
          </li>
        ))}
      </ul>
    </>
  );
}

可选:纯客户端校验钩子(适合单独页面)

如果不需要全局路由拦截,可修正loginRequiredClient为正确的自定义钩子:

"use client";

import { useSession } from "next-auth/react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";

export function useLoginRequiredClient() {
  const { data: session, status } = useSession();
  const router = useRouter();

  useEffect(() => {
    // 未登录状态下跳转到首页
    if (status === "unauthenticated") {
      router.push("/");
    }
  }, [status, router]);

  return { session, status };
}

在客户端页面中使用:

"use client";
import { useLoginRequiredClient } from "@/app/lib/loginRequiredClient";
// ...其他导入

export default function CustomersPage() {
  const { session, status } = useLoginRequiredClient();

  if (status === "loading") {
    return <div>加载中...</div>;
  }

  // ...后续逻辑
}

关键说明

  • 服务器端校验优先:服务器端的路由组拦截是最安全的方案,避免客户端校验被绕过
  • 客户端useSession仅用于处理前端状态(如加载中、用户信息展示),核心权限控制交给服务器端
  • 移除客户端组件中对getServerSession的调用,该方法仅能在服务器环境运行

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 12:50:58