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

Next.js App Router中如何实现自动登出?

Next.js App Router中如何实现自动登出?

Hi Anuj,我来帮你搞定这个token过期自动登出的问题~ 从你给出的登录信息和Next-Auth配置来看,核心问题是Next-Auth默认只会校验它自身生成的exp字段,不会主动检查你自定义登录token的过期时间。我们可以从后端配置校验和前端主动监听两个层面来解决:

一、修改Next-Auth配置,让session每次都校验token过期

首先更新你的authOptions,新增jwt和session回调逻辑,每次生成或获取session时主动检查token的有效性:

import { NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github";
import CredentialProvider from "next-auth/providers/credentials";
import type { JWT } from "next-auth/jwt";

export const authOptions: NextAuthOptions = {
  providers: [
    // 保留你现有的其他provider
    CredentialProvider({
      name: "Credentials",
      credentials: {
        email: { label: "邮箱", type: "text" },
        password: { label: "密码", type: "password" }
      },
      async authorize(credentials) {
        // 这里是你的登录校验逻辑,返回包含token和exp的用户数据
        const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/login`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            email: credentials?.email,
            password: credentials?.password
          })
        });
        const user = await res.json();

        // 登录成功则返回用户数据,失败返回null
        if (res.ok && user) return user;
        return null;
      }
    })
  ],
  // 配置JWT回调,处理token校验
  callbacks: {
    async jwt({ token, user }) {
      // 首次登录时,把自定义token和它的过期时间存入JWT
      if (user) {
        return {
          ...token,
          customToken: user.token,
          customTokenExp: user.exp // 注意这里是你登录返回token里的exp字段
        };
      }

      // 每次获取JWT时,检查自定义token是否过期
      const currentTimestamp = Math.floor(Date.now() / 1000);
      if (token.customTokenExp && currentTimestamp > token.customTokenExp) {
        // 过期则返回null,让Next-Auth自动清除session
        return null;
      }

      return token;
    },
    async session({ session, token }) {
      // 把自定义token挂载到session,方便前端使用
      if (token.customToken) {
        session.user.customToken = token.customToken;
        session.user.customTokenExp = token.customTokenExp;
      }

      // 标记过期的session为无效
      if (token.customTokenExp && Math.floor(Date.now() / 1000) > token.customTokenExp) {
        session.expires = new Date(0).toISOString();
      }

      return session;
    }
  },
  session: { strategy: "jwt" }, // 必须设置为jwt策略才能使用上述回调
  secret: process.env.NEXTAUTH_SECRET, // 记得在.env文件配置这个密钥
};

二、前端全局监听session状态,触发自动登出

在App Router的客户端组件(比如根布局layout.tsx)里,用useSession钩子监听session变化,一旦session无效就自动登出:

"use client";

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

export default function RootLayout({ children }: { children: React.ReactNode }) {
  const { data: session, status } = useSession({
    required: true,
    // 当session变为未认证时触发
    onUnauthenticated() {
      signOut({ callbackUrl: "/login" });
    }
  });

  // 定时检查session有效性(可选,作为额外保障)
  useEffect(() => {
    const checkSessionInterval = setInterval(() => {
      if (session?.user?.customTokenExp) {
        const currentTime = Math.floor(Date.now() / 1000);
        if (currentTime > session.user.customTokenExp) {
          signOut({ callbackUrl: "/login" });
          clearInterval(checkSessionInterval);
        }
      }
    }, 30000); // 每30秒检查一次

    return () => clearInterval(checkSessionInterval);
  }, [session]);

  return (
    <html lang="zh-CN">
      <body>{children}</body>
    </html>
  );
}

三、后端API配合:返回401触发登出

别忘了在你的后端接口里,每次请求都校验token的有效性,如果token过期就返回401 Unauthorized状态码。然后你可以封装一个带认证的请求函数,捕获401时触发登出:

// 封装带认证的API请求函数
export async function authFetch(url: string, options: RequestInit = {}) {
  const session = await getSession();
  const headers = new Headers(options.headers);
  if (session?.user?.customToken) {
    headers.set("Authorization", `Bearer ${session.user.customToken}`);
  }

  const res = await fetch(url, {
    ...options,
    headers
  });

  // 捕获401状态,触发登出
  if (res.status === 401) {
    await signOut({ callbackUrl: "/login" });
    return null;
  }

  return res.json();
}

这样一套组合拳下来,不管是session自动校验、定时检查还是API请求失败,都能确保用户在token过期后自动登出啦~

备注:内容来源于stack exchange,提问作者Anuj Todankar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.17 11:23:02