【问题标题】:Firestore query permission deniedFirestore 查询权限被拒绝
【发布时间】:2018-06-29 09:51:45
【问题描述】:

我在构建 Firestore 安全规则时遇到了问题。具体来说:

db.collection("boards").whereEqualTo("roles.${me.email}", "admin") 总是失败并出现PERMISSION_DENIED 错误。

奇怪的是,获取单个文档就像一种魅力。据我了解,此查询不会违反我的任何安全规则。它应该始终返回 isAnyRole(resource) 函数的子集合。

我的安全规则:

service cloud.firestore {
match /databases/{database}/documents {

function isSignedIn() {
    return request.auth != null;
}

match /boards/{board} {

    //Board has owner and 3 possible roles:
    //* admin: can do everything, like an owner, but can be removed
    //* idea_reader: has read only access to the board and its ideas
    //* idea_editor: har write access to ideas and read access to the board itself
    function roles() {
    return ['admin', 'idea_reader', 'idea_editor'];
        }

    function isOwner(rsc) {
    return request.auth.uid == rsc.data.ownerId;
  }

  function getRole(rsc) {
    return rsc.data.roles[request.auth.token.email];
  }

  function isOneOfRoles(rsc, array) {
    // Determine if the user is one of an array of roles
    return isSignedIn() && (getRole(rsc) in array);
  }

  function isAnyRole(rsc) {
    //Determine if user is any role or owner. 
    return isOwner(rsc) || isOneOfRoles(rsc, roles());
  }

  function isValidNewBoard() {
    // Valid if story does not exist and data is set correctly
    return resource == null
                && request.resource.data.ownerId == request.auth.uid
          && request.resource.data.name != null;
  }

  function isValidBoardUpdate() {
    // Valid if ownerId didn't change and called by owner of admin
    return (isOwner(resource) || isOneOfRoles(resource, ['admin']))
                    && resource.data.ownerId == request.resource.data.ownerId
                    && request.resource.data.name != null;
  }

  // Owner and admin can edit. Owner can delete. 
  allow write: if isValidNewBoard() || isValidBoardUpdate();
  allow delete: if isOwner(resource);

  // Owner and any role can read 
  allow read: if isAnyRole(resource);

  match /ideas/{idea} {
    // Any role can read ideas 
    allow read: if isAnyRole(get(/databases/$(database)/documents/boards/$(board)));

    //Owner, admin and idea_editor can edit ideas
    allow write: if isOwner(get(/databases/$(database)/documents/boards/$(board)))
                                || isOneOfRoles(get(/databases/$(database)/documents/boards/$(board)), ['admin', 'idea_editor']);
  }

}

match /{document=**} {
  allow read, write: if false;
}

}
}

【问题讨论】:

  • 来自文档:在编写查询以检索文档时,请记住,安全规则不是过滤器——查询是全部或全部。这意味着:如果在此集合中您有权访问某些文档但无权访问其他一些文档,则查询将失败。 firebase.google.com/docs/firestore/security/rules-query
  • 我可以看到的是,您正在尝试查询您是管理员的所有文档,并且您希望您的安全规则会过滤非管理员的文档。这是不可能的。
  • 我明白你的意思。那么为什么db.collection("boards").whereEqualTo("ownerId", me.id) 可以正常工作呢?它会过滤掉我不是所有者的板。

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


【解决方案1】:

问题出在查询上,而不是安全规则上。这是一个小棘手的事情,没有很好的记录。那么让我们看看我的查询:

db.collection("boards").whereEqualTo("roles.${me.email}", "admin")

假设电子邮件是n.surname@gmail.com。然后查询如下所示:

db.collection("boards").whereEqualTo("roles.n.surname@gmail.com", "admin")

因此,Firestore 首先尝试访问对象roles,然后尝试访问roles 内的对象n,依此类推。这就是查询被拒绝的原因——它不符合定义的安全规则。如果它有效,我可以拥有我不应该访问的查询板。

要解决这个问题,我必须使用 FieldPath 修改查询:

db.collection("boards").whereEqualTo(FieldPath.of("roles", me.email), ROLE_ADMIN)

【讨论】:

    【解决方案2】:

    模板文字不应该是

    db.collection("boards").whereEqualTo(`roles.${me.email}`, "admin")
    

    而不是

    db.collection("boards").whereEqualTo("roles.${me.email}", "admin")
    

    因此,当您尝试查询安全规则未涵盖的文档时 (me.email !== "${me.email}"; me.email === `${me.email} `),你总是会得到一个权限被拒绝的错误。

    【讨论】:

    • 我没有明确提及。它是用 Kotlin 而不是 Javascript 编写的 Android 原生应用程序。 "roles.${me.email}" 是正确的。我在这里发帖之前自己仔细检查了一遍:D
    猜你喜欢
    • 1970-01-01
    • 2020-11-17
    • 2019-03-20
    • 2020-09-12
    • 2019-02-24
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 2020-10-25
    相关资源
    最近更新 更多