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

Firebase Realtime Database匿名认证后读取数据返回null问题

问题背景

我是初级开发,需求是用户打开首页自动完成匿名身份认证,认证成功后从Realtime Database拉取数据,仅允许用户读取和自身uid匹配路径下的数据。

当前配置的数据库安全规则:

{
  "rules": {
      "$uid": {
        ".read": "auth != null && auth.uid == $uid",
        ".write": "false",
      }
  }
}

数据库结构参考对应截图。

全局AuthContext中的匿名登录逻辑:

export const AuthContextProvider = ({ children }: Props) => {
  React.useEffect(() => {
    signInAnonymously(auth)
      .then(() => {
        // 登录完成逻辑
      })
      .catch((error) => {
        const errorCode = error.code;
        const errorMessage = error.message;
        // 错误处理
      });
  }, []);

  const values = {};

  return <AuthContext.Provider value={values}>{children}</AuthContext.Provider>;
};

访问/crew页面时,getStaticProps会触发fetchPlanetsInfo方法:

export const getStaticProps: GetStaticProps = async () => {
  const planetInfo = await fetchPlanetsInfo("destinations");

  return {
    props: {
      data: planetInfo,
    },
  };
};
export function fetchPlanetsInfo(query: string) {
  let dataArr: any = [];

  try {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        const uid = user.uid;
        const databaseCall = ref(db, uid + "/" + query);

        onValue(databaseCall, (snapshot) => {
          const data = snapshot.val();
          dataArr.push(data);
        });
      } else {
        console.log("user is signout");
        // 未登录处理
      }
    });
  } catch (error) {
    console.log(error);
  }

  return dataArr.flat();
}

故障表现:无法从数据库获取数据,fetchPlanetsInfo返回null,初步怀疑是安全规则配置问题。

问题排查与修复

你的安全规则权限判断逻辑本身没有问题,故障是三个错误叠加导致的:

  1. 安全规则存在语法错误
    你写的规则中.write: "false"末尾多了一个多余的逗号,Realtime Database规则采用类JSON语法,不允许键值对后存在尾逗号,会直接导致规则解析失败,所有数据库请求默认被拒绝。先删除这个逗号再重新发布规则。

  2. 数据请求位置错误
    Next.js的getStaticProps是项目构建阶段在服务端执行的代码,根本不会在用户浏览器端运行:

    • 执行时拿不到浏览器端的匿名登录状态
    • 你写在AuthContext里的匿名登录逻辑是客户端侧的,构建阶段根本不会执行
    • 服务端环境下的onAuthStateChanged无法监听到客户端的用户登录态,自然拿不到对应uid
      拉取用户私有数据不能放在getStaticProps中,改成在客户端页面组件内,确认拿到用户登录态后再发起请求;如果要做服务端渲染,改用getServerSideProps,配合客户端传递的id token完成服务端认证后再查库。
  3. 异步逻辑写法错误
    onAuthStateChanged和onValue都是异步订阅监听器,你当前的写法是刚注册完监听器就立刻执行return dataArr.flat(),此时异步回调还没触发,dataArr是空数组,根本等不到数据返回。
    正确写法需要返回Promise,等拿到数据后再返回结果,参考如下改法:

    export async function fetchPlanetsInfo(query: string) {
      // 等待获取当前登录用户
      const user = await new Promise((resolve, reject) => {
        const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
          unsubscribe(); // 拿到一次用户状态就取消订阅,避免内存泄漏
          resolve(currentUser);
        }, reject);
      });
    
      if (!user) throw new Error("用户未登录");
      
      // 读取对应路径数据
      const dbRef = ref(db, `${user.uid}/${query}`);
      const snapshot = await get(dbRef); // 单次读取用get方法,不需要持续订阅的场景不要用onValue
      return snapshot.val();
    }
    

    补充:如果只需要读取一次数据,不要用onValue,它是用来持续监听数据实时变化的,单次读取用get()即可,避免不必要的内存泄漏。

全部改完后,先手动触发匿名登录确认拿到uid,再核对数据库中对应用户uid路径下确实存在destinations节点,避免路径拼写错误。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 20:39:16