刷新令牌过期时如何在Next.js中间件中直接登出(Auth.js)
直接在Next.js中间件处理刷新令牌过期并登出的实现方案
核心结论
完全可以跳过中间客户端页面,直接在Next.js中间件完成登出操作,并携带会话过期提示重定向到登录页。删除Auth.js的令牌Cookie是合法且有效的实现方式,但要注意完整清理所有会话相关Cookie,同时正确传递提示信息。
具体实现步骤
在jwt回调中标记刷新令牌过期状态
当检测到刷新令牌过期时,在JWT payload中加入refreshTokenExpired: true的标识,让中间件能直接识别该状态:async jwt({ token, account }) { if (account && account.refresh_token) { token.refreshToken = account.refresh_token; token.accessTokenExpires = Date.now() + account.expires_in * 1000; } // 访问令牌未过期,直接返回 if (Date.now() < token.accessTokenExpires) { return token; } // 尝试刷新令牌 try { const response = await fetch(`${process.env.AUTH_API_URL}/refresh`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ refreshToken: token.refreshToken }), }); const newTokens = await response.json(); if (!response.ok) throw new Error(); return { ...token, accessToken: newTokens.access_token, refreshToken: newTokens.refresh_token, accessTokenExpires: Date.now() + newTokens.expires_in * 1000, }; } catch (error) { // 刷新令牌过期,标记状态 return { ...token, refreshTokenExpired: true }; } }在middleware.ts中拦截并处理过期状态
中间件里解析JWT后,检查refreshTokenExpired标识,若是则清理Auth.js的所有相关Cookie,再重定向到带提示参数的登录页:import { NextResponse } from 'next/server'; import type { NextRequest } from 'next/server'; import { getToken } from 'next-auth/jwt'; export async function middleware(request: NextRequest) { const token = await getToken({ req: request, secret: process.env.NEXTAUTH_SECRET }); // 仅处理已登录但刷新令牌过期的请求 if (token?.refreshTokenExpired) { const loginUrl = new URL('/login?error=session_expired', request.url); const response = NextResponse.redirect(loginUrl); // 清理Auth.js的会话及CSRF令牌Cookie(覆盖HTTP/HTTPS场景) response.cookies.delete('next-auth.session-token'); response.cookies.delete('__Secure-next-auth.session-token'); response.cookies.delete('next-auth.csrf-token'); response.cookies.delete('__Secure-next-auth.csrf-token'); return response; } // 正常路由逻辑放行 return NextResponse.next(); } export const config = { matcher: ['/dashboard/:path*', '/profile/:path*'], // 仅对需要认证的路由生效 };在登录页显示会话过期提示
登录页通过searchParams获取重定向带来的error参数,判断后显示对应的提示:import { useSearchParams } from 'next/navigation'; export default function LoginPage() { const searchParams = useSearchParams(); const error = searchParams.get('error'); return ( <div className="login-wrapper"> {error === 'session_expired' && ( <div className="alert alert-warning">您的会话已过期,请重新登录</div> )} {/* 登录表单代码 */} </div> ); }
关键注意事项
- Cookie清理完整性:Auth.js在HTTP和HTTPS环境下使用的Cookie名称不同,必须同时删除普通和
__Secure-前缀的Cookie,避免残留会话信息。 - NEXTAUTH_SECRET配置:中间件调用
getToken必须配置正确的NEXTAUTH_SECRET,否则无法解析JWT内容。 - 避免重定向循环:确保中间件的
matcher不包含登录页路径,否则会陷入无限重定向。
内容的提问来源于stack exchange,提问作者fleskara
相关产品推荐
相关产品推荐

