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

NextJS 13.0中使用Firebase-admin如何刷新过期会话Token?

在Next.js中处理Firebase Token过期刷新的正确流程

首先要明确:Firebase Admin在服务端验证Token过期后,无法直接在中间件里刷新Token——因为刷新操作依赖客户端的Firebase Auth实例(用户的刷新Token仅存在客户端Auth状态中)。你之前想调用客户端getIdToken()的思路是对的,但需要配合服务端响应逻辑完成闭环。

具体实现步骤

1. 中间件检测Token过期并返回标识

在middleware.ts中,当Firebase Admin验证Token失败且错误为token-expired时,返回自定义响应头或重定向到特定页面,通知客户端需要刷新Token。

示例代码:

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { auth } from '@/lib/firebase-admin'; // 你的Firebase Admin实例

export async function middleware(request: NextRequest) {
  const sessionCookie = request.cookies.get('session')?.value;

  if (!sessionCookie) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  try {
    await auth.verifySessionCookie(sessionCookie, true);
    return NextResponse.next();
  } catch (error: any) {
    if (error.code === 'auth/id-token-expired' || error.code === 'auth/session-cookie-revoked') {
      // 返回自定义头,告知客户端Token过期
      const response = NextResponse.next();
      response.headers.set('X-Token-Expired', 'true');
      return response;
    }

    // 其他错误跳转到登录页
    return NextResponse.redirect(new URL('/login', request.url));
  }
}

2. 客户端监听并触发Token刷新

在全局组件(如app/layout.tsx)或页面组件中,监听服务端返回的X-Token-Expired头,调用Firebase客户端的getIdToken(true)强制刷新Token,再通过API更新Cookie。

示例代码(客户端组件):

'use client';

import { useEffect } from 'react';
import { getAuth, getIdToken } from 'firebase/auth';
import { auth as firebaseAuth } from '@/lib/firebase-client'; // 你的Firebase客户端实例

export default function TokenRefreshHandler() {
  useEffect(() => {
    async function checkAndRefreshToken() {
      const response = await fetch('/api/check-token', { method: 'HEAD' });
      if (response.headers.get('X-Token-Expired') === 'true') {
        try {
          const auth = getAuth(firebaseAuth);
          const user = auth.currentUser;
          if (user) {
            // 强制刷新Token
            const newIdToken = await getIdToken(user, true);
            // 调用API更新Session Cookie
            await fetch('/api/update-session', {
              method: 'POST',
              headers: { 'Content-Type': 'application/json' },
              body: JSON.stringify({ idToken: newIdToken })
            });
            // 刷新页面让中间件重新验证
            window.location.reload();
          } else {
            window.location.href = '/login';
          }
        } catch (error) {
          console.error('刷新Token失败:', error);
          window.location.href = '/login';
        }
      }
    }

    checkAndRefreshToken();
  }, []);

  return null;
}

3. 编写更新Session的API路由

创建app/api/update-session/route.ts,接收客户端的新Token,用Firebase Admin生成新的Session Cookie并设置到响应中。

示例代码:

import { NextResponse } from 'next/server';
import { auth } from '@/lib/firebase-admin';

export async function POST(request: Request) {
  const { idToken } = await request.json();

  try {
    const expiresIn = 60 * 60 * 24 * 14 * 1000; // 14天有效期
    const sessionCookie = await auth.createSessionCookie(idToken, { expiresIn });

    const response = NextResponse.json({ success: true });
    response.cookies.set('session', sessionCookie, {
      maxAge: expiresIn / 1000,
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'strict',
      path: '/'
    });

    return response;
  } catch (error) {
    return NextResponse.json({ error: '更新会话失败' }, { status: 401 });
  }
}

关键注意点

  • 禁止在中间件调用客户端Firebase方法:中间件运行在边缘/服务端,无浏览器环境,无法访问客户端Auth状态。
  • getIdToken(true)的作用:传入true强制刷新Token,否则返回缓存的未过期Token。
  • Cookie安全设置:必须开启httpOnly: true防XSS,生产环境设置secure: true确保HTTPS传输。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 22:57:19