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

