无需重载页面的Firebase身份验证JWT自动刷新问题咨询
JWT刷新后请求仍报过期问题的解决方案
核心问题原因
- 刷新获取新token后未同步更新cookie存储:你的代码仅在初始化
onAuthStateChanged触发、拿到初始token时执行了cookie写入逻辑,定时器触发刷新、拿到新token后,仅更新了React状态token,没有同步更新cookie中的token值。如果你的接口请求是从cookie读取token携带,请求自然会使用旧的已过期token,手动刷新页面后会重新触发onAuthStateChanged逻辑写入新token,所以问题会临时修复。 - 存在闭包陷阱:
setTimeout回调中引用的timeToExpiry可能存在陈旧闭包值问题,极端场景会导致刷新时机偏差。 - 未兼容
currentUser为空场景:异步执行getIdToken时,firebase.auth().currentUser可能已被置空,直接调用方法会抛出异常。
修复后代码
React.useEffect(() => { // 存储定时器ID,用于卸载时清理 let refreshTimer = null; const unsubscribe = firebase.auth().onAuthStateChanged(async (auth) => { if (auth) { const token = await auth.getIdToken(); setToken(token) nookies.destroy({}, "token"); nookies.set({}, "token", token, { path: "/" }); setAuth(auth); const val = jwt_decode(token) as any; const exp = Number(val.exp); let timeToExpiry = moment(exp * 1000 - 1000 * 5).diff(moment()); const updateToken = () => { refreshTimer = setTimeout(async () => { console.log("REFRESHING TOKEN"); const currentUser = firebase.auth().currentUser; // 兼容用户已登出场景,不再执行刷新 if (!currentUser) return; try { const newToken = await currentUser.getIdToken(true); setToken(newToken); // 新增:同步更新cookie中的token nookies.destroy({}, "token"); nookies.set({}, "token", newToken, { path: "/" }); const val = jwt_decode(newToken) as any; const exp = Number(val.exp); timeToExpiry = moment(exp * 1000 - 1000 * 5).diff(moment()); updateToken(); } catch (e) { // 刷新失败走登出逻辑 await firebase.auth().signOut(); } }, timeToExpiry) } updateToken(); } else { setToken(""); nookies.destroy({}, "token"); setAuth(null); // 登出时清理定时器 if (refreshTimer) clearTimeout(refreshTimer); var provider = new firebase.auth.GoogleAuthProvider(); provider.setCustomParameters({ prompt: 'select_account' }); firebase.auth().signInWithRedirect(provider); } }) // 组件卸载时清理监听和定时器 return () => { unsubscribe(); if (refreshTimer) clearTimeout(refreshTimer); } }, [])
额外优化建议
- 接口请求时优先从React状态读取最新token,或者每次请求前直接调用
firebase.auth().currentUser?.getIdToken()实时获取有效token,避免依赖静态存储的过期值 - 可以给接口请求添加响应拦截器,收到401过期错误时主动触发一次token刷新,刷新成功后重发原请求,进一步降低过期概率
内容的提问来源于stack exchange,提问作者meds
相关产品推荐
相关产品推荐

