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

Next.js(App Dir)中如何用Next-Auth实现会话过期自动登出?

Next.js App Dir 实现无操作自动登出方案

先解决 Session Null 错误

任何读取会话数据的场景,必须先做空值校验,避免直接访问 null 属性:

服务器组件中(如页面、布局)

import { getServerSession } from 'next-auth/next';
import { authOptions } from '@/auth';
import { redirect } from 'next/navigation';

export default async function DashboardPage() {
  const session = await getServerSession(authOptions);
  
  if (!session) {
    redirect('/login');
  }

  return <div>欢迎回来,{session.user?.name}</div>;
}

客户端组件中

'use client';

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

export default function Profile() {
  const { data: session } = useSession();
  const router = useRouter();

  useEffect(() => {
    if (!session) router.push('/login');
  }, [session, router]);

  if (!session) return null;

  return <div>你的邮箱:{session.user.email}</div>;
}

实现无操作自动登出核心逻辑

创建客户端组件 AutoLogout.tsx,监听用户交互并管理超时定时器:

'use client';

import { useEffect, useState } from 'react';
import { signOut } from '@/auth';
import { useSession } from 'next-auth/react';

// 自定义超时时间(示例为30分钟)
const AUTO_LOGOUT_DURATION = 30 * 60 * 1000;

export default function AutoLogout() {
  const { data: session } = useSession();
  const [logoutTimer, setLogoutTimer] = useState<NodeJS.Timeout | null>(null);

  // 重置超时定时器
  const resetTimer = () => {
    if (logoutTimer) clearTimeout(logoutTimer);
    const timer = setTimeout(async () => {
      await signOut({ redirect: true, callbackUrl: '/' });
    }, AUTO_LOGOUT_DURATION);
    setLogoutTimer(timer);
  };

  useEffect(() => {
    // 会话不存在时不初始化定时器
    if (!session) return;

    // 监听用户交互事件
    const userEvents = ['mousemove', 'keydown', 'scroll', 'touchstart'];
    userEvents.forEach(event => window.addEventListener(event, resetTimer));

    // 初始化定时器
    resetTimer();

    // 清理函数:移除监听并销毁定时器
    return () => {
      userEvents.forEach(event => window.removeEventListener(event, resetTimer));
      if (logoutTimer) clearTimeout(logoutTimer);
    };
  }, [session, logoutTimer]);

  return null; // 组件无需渲染内容
}

在根布局中引入自动登出组件

根布局默认是服务器组件,直接导入客户端组件即可:

// app/layout.tsx
import AutoLogout from '@/components/AutoLogout';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="zh-CN">
      <body>
        {children}
        <AutoLogout />
      </body>
    </html>
  );
}

说明之前方案的问题

  1. Layout 中重定向失败:App Dir 布局默认是服务器组件,无法监听客户端交互;若用服务器端 redirect,只能处理初始会话校验,无法应对会话过期后的客户端无操作场景,必须结合客户端组件实现自动登出。
  2. useEffect 循环问题:之前未正确清理定时器,或依赖项设置错误,导致会话变化后反复触发 useEffect。上述代码仅在会话存在时初始化定时器,且清理函数会移除监听并销毁定时器,彻底避免循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:53:33