【问题标题】:Cloud Firestore security rules not workingCloud Firestore 安全规则不起作用
【发布时间】:2021-11-22 07:11:27
【问题描述】:

我正在尝试提高 Firestore 数据库的安全性,但我对此感到绝望。我已经尝试编辑它几个小时以尝试它是否可以工作,但它不断出错或拒绝访问。规则游乐场表明它应该工作..但它没有。

我正在尝试使用用户 /environment/STABLE/users/RMwv3mmP4RIOVqPOsa77 访问 /environment/STABLE/route_sets/w3TBJrovQbgFPr2GFfug。用户有一个名为 db_role 的字段,其中包含字符串 ADMIN。 route_sets 中的文档包含一个名为 _permissions_read 的数组,其值为 TEST_NOTHINGADMIN

使用规则游乐场测试它可以工作,但是当我通过我的 Angular 应用程序尝试它时,我得到“错误 FirebaseError:缺少或不足的权限。”。对于身份验证,我将 Firebase 身份验证与自定义提供程序一起使用,uid 是用户表中的文档 ID。

Cloud Firestore 上“监控规则”选项卡上的信息 -> 规则似乎表明当前规则(如下所示)在尝试访问 route_set 时产生错误。

rules_version = "2";
service cloud.firestore {
  match /databases/{database}/documents {
    match /environment/{environment}/{collectionName}/{documentId} {
        allow read, write: if request.auth != null && collectionName == "route_sets" && checkPermissionRead(environment, collectionName, documentId);
        allow read: if request.auth != null && collectionName != "route_sets";
        allow write, delete: if request.auth != null;
      
      function checkPermissionRead(environment, collectionName, documentId) {
          return get(/databases/$(database)/documents/environment/STABLE/users/$(request.auth.uid)).data.db_role in get(/databases/$(database)/documents/environment/$(environment)/$(collectionName)/$(documentId)).data._permissions_read;
        }
    }

    match /environment/STABLE/licenseholders/{document=**} {
      allow read: if true
      allow read, write: if request.auth != null;
    }
    match /environment/STABLE/users/{document=**} {
      allow read: if true
      allow read, write: if request.auth != null;
    }
  }
}

Angular 应用代码:

import {Component, OnDestroy, OnInit} from '@angular/core';
import {AngularFirestore} from '@angular/fire/firestore';
import {AngularFireAuth} from '@angular/fire/auth';

@Component({
  selector: 'app-example-security-rules',
  template: `<span *ngFor="let set of routeSets"></span>`,
  styles: [``],
  providers: [ ]
})
export class ExampleSecurityRulesComponent implements OnInit {
  routeSets = [];

  constructor(private db: AngularFirestore,
              public afAuth: AngularFireAuth) {
  }

  ngOnInit() {
    this.afAuth.onAuthStateChanged(async (user) => {
      if (user) {
        this.db.collection<any>('environment/STABLE/route_sets').get().subscribe((d) => {
          d.forEach(docT => {
            this.routeSets.push({__document__key: docT.id, ...docT.data()});
          });
        });
      }
    });
  }

}

新的代码和安全规则有效:

安全规则

rules_version = "2";
service cloud.firestore {
  match /databases/{database}/documents {
    match /environment/{environment}/{collectionName}/{documentId} {
      allow read: if request.auth != null && collectionName != "route_sets";
        allow write, delete: if request.auth != null;
    }

match /environment/{environment}/route_sets/{document=**} {
    allow read, write: if request.auth != null && checkPermissionRead(environment);
  
  function checkPermissionRead(environment) {
        let user = get(/databases/$(database)/documents/environment/$(environment)/users/$(request.auth.uid)).data;
                return user.db_role in resource.data._permissions_read && user.licenseholder_id == resource.data.licenseholder_id;
        }
  
}
match /environment/STABLE/licenseholders/{document=**} {
  allow read: if true
  allow read, write: if request.auth != null;
}
match /environment/STABLE/users/{document=**} {
  allow read: if true
  allow read, write: if request.auth != null;
}
  }
}

角度

this.db.collection<any>('environment/STABLE/route_sets').ref.where('licenseholder_id', '==', environment.licenseholder_id)
            .where('_permissions_read', 'array-contains', DatabaseRoles.ADMIN).get().then((d) => {
          d.forEach(docT => {
            this.routeSets.push({__document__key: docT.id, ...docT.data()});
          });
});

【问题讨论】:

  • 请编辑您的问题以包含可以解决问题的最少代码,而不是描述您的代码。如果在该代码中显示它满足安全规则,它也会有所帮助(因此:显示 firebase.auth().currentUser 具有值
  • 嘿弗兰克,感谢您的回复。我添加了最少的代码,这有帮助吗?
  • 谢谢,这有帮助,虽然我还不知道出了什么问题。如果禁用checkPermissionRead调用,读取是否成功?
  • 是的,在没有函数调用的情况下读取成功。 (编辑规则:pastebin.com/hP0xEsUb

标签: javascript firebase google-cloud-firestore firebase-security


【解决方案1】:

如果我正确理解了用户案例,您将尝试阅读整个集合,然后过滤规则中的各个文档。

那是行不通的,就像rules are not filters。相反,规则仅在查询开始时检查是否允许读取操作,而不检查单个文档 - 因为这不会在性能和成本方面进行扩展。

因此,您的规则中的 get() 调用仅在您阅读单个文档时有效,而不是在您请求一系列文档时(称为规则中的 list 操作)。

如果您想安全地读取一系列文档,则必须在代码中构建正确的查询,然后使用规则 secure that query。不幸的是,没有办法从查询中的规则中获得与您的 get() 操作等效的操作。

安全执行此类操作的唯一方法是复制每个 route_sets 文档下的权限数据,以便您的规则可以在那里检查它 - 并且他们可以验证您传递的条件是否正确仅请求您获得授权的文档的查询。

【讨论】:

  • 我已经将权限数据添加到 route_sets 集合中的每个文档,但是因为我没有在查询中过滤 _permissions_read,所以它不起作用。感谢 dankjewel 弗兰克的帮助,他永远不会发现这是导致它失败的原因。
猜你喜欢
  • 1970-01-01
  • 2019-09-27
  • 2019-01-31
  • 1970-01-01
  • 1970-01-01
  • 2018-03-19
  • 2021-05-12
  • 2019-09-06
相关资源
最近更新 更多