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

Firebase手机号认证提交资料报auth/user-token-expired错误

问题原因

你碰到的auth/user-token-expired报错是因为当前登录用户的身份令牌已过期,Firebase判定会话失效,所以执行updateProfile、updateEmail这类需要鉴权的操作时会直接拦截,操作失败后会话自动销毁,就会出现用户被自动登出的情况。
你现有代码有三个直接触发问题的硬伤:

  • 所有异步操作(更新资料、更新邮箱、调用signUp方法、页面跳转)全是同步并行执行的,根本没等前一步操作完成就跑下一段,甚至操作还没执行完就直接跳路由,很容易打断Firebase的鉴权状态校验流程,导致令牌提前失效
  • updateEmail属于Firebase Auth的高敏感操作,要求用户必须是最近刚完成登录的状态才能执行,手机号验证码登录完成后如果停留时间稍长、或者中间有其他状态变更,令牌就会过期,直接调接口必然报错
  • 输入框change事件里错误加了e.preventDefault(),容易引发意外的页面行为打断鉴权流程;另外还冗余引入了lodash的update方法但从未使用,虽然不直接触发报错,但属于无意义的代码冗余。
修复方案

第一步:修正异步执行逻辑,所有操作按顺序等待执行结果

绝对不能在异步操作没完成的时候就跳页,必须等所有资料更新操作走完、确认成功之后再做路由跳转,把原来的并行逻辑改成串行async/await写法,修正后的核心方法代码如下:

// 改造邮箱更新方法,等待执行结果再返回
const updateEmailUser = async () => {
  try {
    await updateEmail(auth.currentUser, email);
    console.log("邮箱更新成功");
    return true;
  } catch (error) {
    console.log("邮箱更新失败", error);
    // 捕获令牌过期、需要最近登录类的错误往上抛出
    if (error.code === 'auth/user-token-expired' || error.code === 'auth/requires-recent-login') {
      throw error;
    }
    return false;
  }
};

// 改造资料更新方法,先更新昵称再更新邮箱,全部执行完再返回
const updateUserProfile = async () => {
  try {
    await updateProfile(auth.currentUser, {
      displayName: name,
    });
    console.log("资料更新成功", name, email);
    await updateEmailUser();
    return true;
  } catch (error) {
    console.log("资料更新失败", error);
    throw error;
  }
};

// 改造提交方法,全流程等待执行结果,失败就终止后续跳页逻辑
const handleSubmit = async (e) => {
  e.preventDefault();
  try {
    // 等待用户资料更新完成
    await updateUserProfile();
    // 等待自定义signUp业务逻辑执行完成
    await signUp(name, userType, email);
    // 所有操作成功后再跳转路由
    const path = userType === "salonOwner" ? "/addBuisnessDetails" : "/salonsNearby";
    navigate(path, { replace: true });
  } catch (err) {
    // 碰到登录过期错误,弹出提示引导用户重新做身份验证即可
    if (err.code === 'auth/user-token-expired' || err.code === 'auth/requires-recent-login') {
      console.log("登录状态已过期,请重新验证身份");
    }
    console.log("提交失败", err);
  }
};

第二步:处理敏感操作的最近登录校验要求

Firebase规定修改邮箱、修改密码、删除账号这类操作,必须要求用户在几分钟内刚完成登录鉴权才能执行,如果用户从手机号验证完成到填完表单提交的间隔太长,就会触发令牌过期。碰到这个情况不要直接报错登出,要调用reauthenticateWithCredential方法,用用户之前手机号验证环节留存的PhoneAuthProvider凭证重新做一次身份校验,拿到新的有效令牌之后再重新执行更新操作即可,这个流程不需要用户重复输入验证码,不会影响使用体验。

第三步:修正输入框事件的错误逻辑

把handleChange方法里多余的e.preventDefault()删掉,输入框输入时不需要阻止默认行为,避免意外的页面重载打断鉴权状态,修正后的代码如下:

const handleChange = (e) => {
  // 移除这里的e.preventDefault()
  const { name, value } = e.target;
  switch (name) {
    case "displayname":
      setname(value);
      break;
    case "email":
      setemail(value);
      break;
    default:
      break;
  }
};
额外优化建议
  • 删除代码里冗余引入、从未调用的lodashupdate方法,减少不必要的打包体积和潜在变量冲突
  • 可以在组件挂载时加onAuthStateChanged监听,确认auth.currentUser确实存在且状态有效之后再渲染表单,避免用户已经登出的状态下还能进到这个页面提交表单
  • 所有涉及Firebase Auth的操作,都要等异步返回结果之后再执行后续逻辑,不要提前跳页卸载组件,否则会强制中断正在发送的请求,极易触发令牌失效问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 06:22:04