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
相关产品推荐
相关产品推荐

