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

NextJS使用中间件获取刷新令牌遇页面认证状态异常求助

解决方案

方案1:用中间件异步刷新Token并通过Rewrite传递

Next.js中间件支持异步操作,你可以在中间件里完成Token刷新,然后用NextResponse.rewrite重写当前请求——这个方法不会修改浏览器历史记录,同时能让后续的服务端页面拿到更新后的Token。

具体实现步骤:

  1. 在中间件中检测Access Token是否过期
  2. 若过期且存在Refresh Token,异步调用刷新接口获取新Token
  3. 将新Token写入Cookie,用rewrite返回当前请求的响应

代码示例:

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
  const accessToken = request.cookies.get('accessToken')?.value
  const refreshToken = request.cookies.get('refreshToken')?.value

  // 校验Token是否过期(替换成你自己的校验逻辑)
  const isTokenExpired = accessToken ? checkTokenExpiry(accessToken) : true

  if (isTokenExpired && refreshToken) {
    try {
      // 调用你的刷新接口
      const refreshRes = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/refresh`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ refreshToken }),
      })

      if (refreshRes.ok) {
        const { newAccessToken, newRefreshToken } = await refreshRes.json()

        // 构造新响应,更新Cookie
        const updatedResponse = NextResponse.rewrite(request.url)
        updatedResponse.cookies.set('accessToken', newAccessToken, {
          httpOnly: true,
          secure: process.env.NODE_ENV === 'production',
          sameSite: 'strict',
          maxAge: 15 * 60, // 匹配你的Access Token有效期
        })
        updatedResponse.cookies.set('refreshToken', newRefreshToken, {
          httpOnly: true,
          secure: process.env.NODE_ENV === 'production',
          sameSite: 'strict',
          maxAge: 7 * 24 * 60 * 60, // 匹配你的Refresh Token有效期
        })

        return updatedResponse
      }
    } catch (err) {
      // 刷新失败,按需跳转登录页
      return NextResponse.redirect(new URL('/login', request.url))
    }
  }

  // Token有效或无Refresh Token,继续处理请求
  return NextResponse.next()
}

// 辅助函数:解析Token并检查过期时间
function checkTokenExpiry(token: string): boolean {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]))
    return payload.exp * 1000 < Date.now()
  } catch {
    return true // 解析失败视为过期
  }
}

方案2:服务端组件内前置Token刷新逻辑

如果你的页面是服务端组件,可以在组件渲染前先完成Token刷新,确保后续数据请求用的是有效Token。这种方式不需要依赖中间件,直接在组件内处理:

代码示例:

import { cookies, redirect } from 'next/headers'

async function ProtectedServerPage() {
  const cookieStore = cookies()
  let accessToken = cookieStore.get('accessToken')?.value
  const refreshToken = cookieStore.get('refreshToken')?.value

  // 检查并刷新Token
  if (!accessToken || checkTokenExpiry(accessToken)) {
    if (!refreshToken) redirect('/login')

    const refreshRes = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/refresh`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ refreshToken }),
    })

    if (!refreshRes.ok) redirect('/login')

    const { newAccessToken, newRefreshToken } = await refreshRes.json()
    // 更新Cookie
    cookies().set('accessToken', newAccessToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      maxAge: 15 * 60,
    })
    cookies().set('refreshToken', newRefreshToken, {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      maxAge: 7 * 24 * 60 * 60,
    })
    accessToken = newAccessToken
  }

  // 用新Token请求数据
  const dataRes = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/protected-data`, {
    headers: { Authorization: `Bearer ${accessToken}` },
  })
  const content = await dataRes.json()

  return <div>{content.data}</div>
}

// 复用之前的校验函数
function checkTokenExpiry(token: string): boolean {
  try {
    const payload = JSON.parse(atob(token.split('.')[1]))
    return payload.exp * 1000 < Date.now()
  } catch {
    return true
  }
}

export default ProtectedServerPage

关键注意事项

  • 刷新接口要做好安全防护,比如校验请求来源、添加CSRF Token,避免恶意刷新
  • 中间件的异步操作建议添加超时控制,避免请求长时间挂起
  • 如果是客户端组件,可在useEffect中处理Token刷新,但服务端渲染场景优先用上述两种方案

内容的提问来源于stack exchange,提问作者Trace

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 18:57:01