特定文档的Firestore安全规则

时间:2018-09-27 13:14:19

标签: firebase firebase-authentication google-cloud-firestore firebase-security-rules

我正在尝试以下情况:

  • 除管理员文档外,所有经过身份验证的用户都具有对数据库的读写访问权限。
  • 只有管理员可以读取和写入管理文档。

我的规则:

service cloud.firestore {
  match /databases/{database}/documents {
    //Functions
    function isAuthenticated(){
      return request.auth != null;
    }
    function isAdministrator(){
        return request.auth != null && request.auth.token.name == resource.data.oid;
    }
    //Administrator Identity Check Point
    match /admin/identity {
        allow read, write: if isAdministrator();
        }
    //Allow Reads and Writes for All Authenticated Users
    match /{document=**}{
      allow read, write: if isAuthenticated();
    }
  }//databases/{database}/documents
}//cloud.firestore

我有什么方法可以做到这一点,实际上在测试这些规则时,测试成功是因为标签isAuthenticated()仅调用了/{document=**}。我也尝试过/{document!=/admin/identity},但不起作用。

如何编写遵循此模型的安全规则?

2 个答案:

答案 0 :(得分:1)

也许根据您的默认用户规则,您可以检查集合是否不是管理员,例如:

//Allow Reads and Writes for All Authenticated Users
match /{collection}/{document=**}{
  allow read, write: if (isAuthenticated() && collection != "admin") || isAdministrator();
}

答案 1 :(得分:0)

从6月17日开始,Firebase对Firestore安全规则进行了新的改进。

Firebase blog - 2020/06 - New Firestore Security Rules features

新的地图方法

我们将使用Map.get()来获取"roleToEdit"字段。如果文档没有该字段,则默认为"admin"角色。然后,我们将其与用户自定义声明中的角色进行比较:

allow update, delete: if resource.data.get("roleToEdit", "admin") == request.auth.token.role;

局部变量

假设您通常在授予访问权限之前先检查用户是否满足相同的三个条件:他们是产品的所有者还是管理员用户。

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    function privilegedAccess(uid, product) {
      let adminDatabasePath = /databases/$(database)/documents/admins/$(uid);
      let userDatabasePath = /databases/$(database)/documents/users/$(uid);
      let ownerDatabasePath = /databases/$(database)/documents/$(product)/owner/$(uid);  

      let isOwnerOrAdmin = exists(adminDatabasePath) || exists(ownerDatabasePath);
      let meetsChallenge = get(userDatabasePath).data.get("passChallenge", false) == true;
      let meetsKarmaThreshold = get(userDatabasePath).get("karma", 1) > 5;
      return  isOwnerOrAdmin && meetsChallenge && meetsKarmaThreshold;
    }

    match /products/{product} {
      allow read: if true;
      allow write: if privilegedAccess();
    }

    match /categories/{category} {
      allow read: if true;
      allow write: if privilegedAccess();
    }

    match /brands/{brand} {
      allow read, write: if privilegedAccess();
    }
  }
}

相同条件允许访问三个不同集合中的文档。

三元运算符

这是我们第一次引入if/else控制流,我们希望它可以使规则更加平滑和强大。

这是一个使用三元运算符为写操作指定复杂条件的示例。

用户可以在两种情况下更新文档:首先,如果他们是管理员用户,则需要设置字段overrideReasonapprovedBy。其次,如果他们不是管理员用户,则更新必须包括所有必填字段:

allow update: if isAdminUser(request.auth.uid) ? 
  request.resource.data.keys().toSet().hasAny(["overrideReason", "approvedBy"]) :
  request.resource.data.keys().toSet().hasAll(["all", "the", "required", "fields"])

可以在三元数之前表达它,但这是一个更为简洁的表达。 ;)