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

Firebase规则模拟通过但Google认证后客户端权限拒绝问题排查

排查Firebase权限拒绝问题的原因及解决方案

我帮你梳理下这个权限拒绝问题的核心原因,主要集中在Firebase规则的拼写错误和客户端操作的不匹配上,具体如下:

1. Firebase规则中的致命拼写错误

你的规则里多次使用了auth.id,但Firebase Auth提供的用户唯一标识是auth.uid,auth.id这个属性根本不存在!这直接导致普通用户(非管理员)的读写权限条件永远不成立,触发permission denied。

比如原规则里的这两行:

".read":"root.child('users').child(auth.uid).child('roles/admin').val()===true || root.child('users').child(auth.id).child('id').val()===auth.uid",
".write":"!(root.child('users').child(auth.uid).exists()) || root.child('users').child(auth.uid).child('roles/admin').val()===true || root.child('users').child(auth.id).child('id').val()===auth.uid",

其中root.child('users').child(auth.id)这部分完全无效,因为auth.id是undefined,匹配不到任何节点。

修正后的规则

把所有auth.id替换为auth.uid,修正后的规则如下:

{
  "rules": {
    ".read": "root.child('users').child(auth.uid).child('roles/admin').val() === true || root.child('users').child(auth.uid).child('id').val() === auth.uid",
    ".write": "!root.child('users').child(auth.uid).exists() || root.child('users').child(auth.uid).child('roles/admin').val() === true || root.child('users').child(auth.uid).child('id').val() === auth.uid"
  }
}

2. 客户端操作的逻辑错误:update vs set

当检测到新用户(!user)时,你使用了ref.update(googleUser),但Firebase的update()方法只能修改已存在的节点,如果节点不存在,update()会直接失败,同时触发权限检查的问题。

新用户创建需要用set()方法,它可以创建新节点或替换现有节点,完全匹配你规则里「允许创建不存在的用户节点」的条件。

修正后的Angular代码片段

把ref.update(googleUser)替换为ref.set(googleUser),同时建议你把set的操作也纳入流中,确保动作完成后再分发成功action:

@Effect() loginGetUserInfo$ = this.actions$.pipe(
  ofType(AuthActionTypes.AUTH_LOGIN_GET_USER_INFO),
  map((action: AuthLoginGetUserInfo) => action.user),
  exhaustMap((googleUser: User) => {
    const ref = this.db.object('users/' + googleUser.uid);
    return ref.valueChanges().pipe(
      switchMap((user: User) => {
        if (!user) {
          console.log("Is a new user:", googleUser);
          // 用set创建新用户节点
          return ref.set(googleUser).pipe(
            map(() => new AuthLoginSuccessful(googleUser))
          );
        }
        return of(new AuthLoginSuccessful(user));
      }),
      catchError(error => of(new AuthLoginFailure(error)))
    );
  })
);

3. 额外检查:确保认证状态稳定

另外,建议你在执行数据库操作前,确认用户的认证状态已经稳定。有时候Google认证完成后,Auth状态可能有短暂的延迟,导致auth.uid为null,触发权限拒绝。可以通过AngularFireAuth的authState流来确保用户已认证:

exhaustMap((googleUser: User) => {
  return this.afAuth.authState.pipe(
    take(1), // 只取最新的认证状态
    switchMap(authUser => {
      if (!authUser) {
        throw new Error('User not authenticated');
      }
      const ref = this.db.object('users/' + authUser.uid);
      return ref.valueChanges().pipe(/* 后续逻辑 */);
    })
  );
})

总结

解决这个问题的核心步骤:

  • 修正Firebase规则中的auth.id拼写错误,改为auth.uid
  • 新用户创建时使用set()而非update()
  • 确保数据库操作前用户已完成认证,auth.uid有效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:29:25