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

Next.js中JWT令牌刷新失败时如何实现登出?

Next.js中JWT令牌刷新失败时如何实现登出?

嘿,我来给你唠唠在Next.js 15搭配next-auth 5的项目里,怎么搞定JWT令牌刷新失败自动登出的事儿~

首先,核心逻辑得在next-auth的jwt回调里动手脚,这个回调就是专门处理令牌生成、刷新这些生命周期逻辑的地方。咱们要在这里尝试刷新过期的令牌,一旦捕获到刷新失败的异常,就通过返回null让next-auth自动帮我们清除会话,实现登出效果。结合你已经写了一部分的回调代码,完整配置大概是这样:

callbacks: {
  // 保留你原来的authorized回调逻辑
  async authorized({ auth, request: { nextUrl } }) {
    const isLoggedIn = !!auth?.user;
    const isOnMenu = nextUrl.pathname.startsWith("/menu");
    if (isOnMenu) {
      return isLoggedIn;
    } else if (isLoggedIn) {
      return Response.redirect(new URL("/menu", nextUrl));
    }
    return true;
  },
  async jwt({ token, account, user, trigger, session }) {
    // 初始登录时,把账号和用户信息存入token
    if (account && user) {
      return {
        accessToken: account.access_token,
        refreshToken: account.refresh_token,
        expiresAt: Date.now() + account.expires_in * 1000,
        user,
      };
    }

    // 令牌还没过期的话,直接返回原token就行
    if (Date.now() < token.expiresAt) {
      return token;
    }

    // 令牌过期了,尝试调用你的刷新令牌API
    try {
      // 这里替换成你项目里实际的刷新接口地址和参数
      const response = await fetch(process.env.NEXT_PUBLIC_REFRESH_TOKEN_URL, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ refreshToken: token.refreshToken }),
      });

      const refreshedTokens = await response.json();

      // 如果接口返回失败,直接抛出错误进入catch分支
      if (!response.ok) throw refreshedTokens;

      // 刷新成功,更新token里的有效期和新令牌
      return {
        ...token,
        accessToken: refreshedTokens.access_token,
        refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,
        expiresAt: Date.now() + refreshedTokens.expires_in * 1000,
      };
    } catch (error) {
      // 刷新失败!返回null让next-auth自动清除当前会话
      console.error("令牌刷新失败,自动登出:", error);
      return null;
    }
  },
  // 配合session回调,当token失效时同步清空前端session数据
  async session({ session, token }) {
    if (token) {
      session.user = token.user;
      session.accessToken = token.accessToken;
    } else {
      // 令牌失效后,把session清空,前端就能感知到未登录状态
      return {};
    }
    return session;
  },
}

光在后端处理还不够,前端可以感知会话状态的变化,给用户更友好的提示。比如用useSession钩子监听登录状态,当会话变成未认证时,提示用户重新登录:

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

export default function Layout() {
  const { data: session, status } = useSession();

  useEffect(() => {
    if (status === "unauthenticated" && !session) {
      alert("会话已过期,请重新登录哦~");
      // 也可以直接跳转到登录页:window.location.href = "/login"
    }
  }, [session, status]);

  return (
    {/* 你的页面布局内容 */}
  );
}

总结下核心思路:在jwt回调里捕获刷新失败的异常,返回null让next-auth自动清除会话;通过session回调同步清空前端session数据;最后在前端监听状态变化给用户提示,一套流程下来就完美实现了刷新失败自动登出的效果。

备注:内容来源于stack exchange,提问作者Diego Rascón

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 16:20:29