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

Firebase Token过期致ASP.NET API调用401未授权问题求助

React + Firebase Auth + C# API 频繁遭遇Firebase ID Token过期401错误排查与解决

我正在开发一个React前端结合Firebase认证、C#后端API的项目,前端通过获取并发送Firebase ID Token进行认证,但发起认证请求时频繁收到401 Unauthorized错误,错误提示为**"Firebase ID token expired"**。原本依赖前端的Token刷新逻辑,但该机制偶尔失效,无法准确定位原因,希望排查Token频繁过期的原因、验证Token处理逻辑的问题,并确认后端配置是否存在遗漏。

前端代码(AuthContext.js)

核心逻辑:

  • makeAuthenticatedRequest:处理带认证的API调用,请求失败时尝试刷新Token并重试
  • getFreshToken:以5分钟为频率限制管理Token刷新
// 此处保留原AuthContext.js代码

后端代码

AuthController.cs

TestProtected端点负责验证Firebase ID Token并检查用户权限:

// 此处保留原AuthController.cs代码

Program.cs配置

// 此处保留原Program.cs代码

遇到的问题

  • 频繁触发401 Unauthorized错误
  • 错误信息明确指向Firebase ID Token过期,预设的getFreshToken()刷新机制偶尔失效

已尝试方案

  • 实现Token刷新机制,在当前Token过期时获取新ID Token
  • 遇到401错误时自动重试一次API请求

问题排查与解决方案

1. Token频繁过期的可能原因

(1)前端刷新时机逻辑错误

Firebase ID Token默认有效期为1小时,若你的getFreshToken是固定5分钟强制刷新,会导致不必要的Token切换;若仅在Token过期后才触发刷新,可能因网络延迟、Token过期时间判断失误,导致发送已过期的Token到后端。

(2)前端缓存与Firebase状态不一致

用户在其他设备登出、Token被Firebase后台吊销时,前端缓存的旧Token未及时清理,发起请求会直接触发过期/无效错误。

(3)后端服务器时间偏差

后端服务器系统时间与Firebase服务器时间偏差超过1分钟,会导致Token验证时被误判为过期。

2. 前端Token处理逻辑的常见错误修正

(1)替换定时刷新为基于过期时间的主动刷新

不要用固定间隔刷新,而是解析Token的过期时间,在剩余10分钟左右主动刷新:

// 解析Token过期时间
const getTokenExpiration = (token) => {
  const payload = JSON.parse(atob(token.split('.')[1]));
  return payload.exp * 1000; // 转为毫秒
};

// 提前刷新Token逻辑
const scheduleTokenRefresh = () => {
  const token = authToken;
  if (!token) return;
  
  const expirationTime = getTokenExpiration(token);
  const refreshTime = expirationTime - 10 * 60 * 1000; // 提前10分钟刷新
  const delay = refreshTime - Date.now();
  
  if (delay > 0) {
    setTimeout(async () => {
      const freshToken = await auth.currentUser.getIdToken(true);
      setAuthToken(freshToken);
      scheduleTokenRefresh(); // 循环调度下一次刷新
    }, delay);
  }
};

(2)利用Firebase内置监听同步Token状态

优先使用onIdTokenChanged监听Token自动更新,替代手动定时逻辑:

useEffect(() => {
  const unsubscribe = auth.onIdTokenChanged(async (user) => {
    if (user) {
      const token = await user.getIdToken(true);
      setAuthToken(token);
      scheduleTokenRefresh(); // 启动刷新调度
    } else {
      setAuthToken(null);
    }
  });

  return unsubscribe;
}, []);

(3)完善401重试逻辑

确保401后获取新Token并重新发起请求:

const makeAuthenticatedRequest = async (url, options = {}) => {
  let token = authToken;
  try {
    const response = await fetch(url, {
      ...options,
      headers: {
        ...options.headers,
        Authorization: `Bearer ${token}`,
      },
    });

    if (response.status === 401) {
      // 强制获取新Token并重试
      const freshToken = await auth.currentUser.getIdToken(true);
      setAuthToken(freshToken);
      return fetch(url, {
        ...options,
        headers: {
          ...options.headers,
          Authorization: `Bearer ${freshToken}`,
        },
      });
    }

    return response;
  } catch (error) {
    throw error;
  }
};

3. 后端配置检查点

(1)Firebase Admin SDK初始化验证

确保Program.cs中正确配置JWT验证:

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(options =>
    {
        options.Authority = $"https://securetoken.google.com/{builder.Configuration["Firebase:ProjectId"]}";
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = true,
            ValidIssuer = $"https://securetoken.google.com/{builder.Configuration["Firebase:ProjectId"]}",
            ValidateAudience = true,
            ValidAudience = builder.Configuration["Firebase:ProjectId"],
            ValidateLifetime = true,
            ClockSkew = TimeSpan.FromMinutes(1) // 允许1分钟时间偏差
        };
    });

注意替换配置项为实际Firebase项目ID。

(2)Token验证依赖Firebase Admin SDK

避免自行解析JWT,直接使用SDK验证:

[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{
    [HttpGet("TestProtected")]
    public async Task<IActionResult> TestProtected()
    {
        var token = Request.Headers.Authorization.ToString().Replace("Bearer ", "");
        try
        {
            var decodedToken = await FirebaseAdmin.Auth.FirebaseAuth.DefaultInstance
                .VerifyIdTokenAsync(token);
            // 权限检查逻辑
            return Ok("Authenticated");
        }
        catch (FirebaseAuthException ex)
        {
            return Unauthorized(ex.Message);
        }
    }
}

(3)服务器时间同步

确保后端服务器开启NTP时间同步,避免因时间偏差导致Token验证失败。

4. 最优解决方案总结

  • 前端优先使用Firebase Auth的onIdTokenChanged监听,自动同步Token状态
  • 基于Token过期时间提前刷新,而非固定间隔
  • 401重试时强制获取新Token,确保请求使用有效凭证
  • 后端依赖Firebase Admin SDK验证Token,不要自行解析JWT
  • 检查服务器时间,确保与标准时间同步

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 15:58:12