【问题标题】:Firestore querying with roles?Firestore 使用角色查询?
【发布时间】:2018-12-03 21:28:07
【问题描述】:

the documentation 中声明您可以通过将字符串与另一个字符串值进行比较来进行查询,例如:

citiesRef.where('name', '>=', 'San Francisco');
citiesRef.where('state', '>=', 'CA').where('state', '<=', 'IN');

然后是roles part in the documentation,它展示了如何在 Firestore 文档中应用角色。但是没有显示如何查询这个..但如上例所示,这应该如下所示:

citiesRef.where(`roles.${user.uid}`, '>', '');

所以上面的这个查询应该返回所有值大于空字符串的文档,对吧?

在我的代码中,我有一个包含一个文档的组织集合:

{
  "name": "MyAmazingCompany",
  "roles": {
    "my-user-uid": "owner"
  }
}

如果我尝试查询我担任此类角色的组织:

organizationsRef.where(`roles.${user.uid}`, '>', '');

我将在浏览器控制台中获得 Uncaught Error in onSnapshot: Error: Missing or insufficient permissions.(使用 firebase npm 包版本 5.1.0 并尝试过 5.0.3)。

只是为了确保我应该有权访问该文档,以下查询经过测试,它可以正常工作并返回该组织。

organizationsRef.where(`roles.${user.uid}`, '==', 'owner');

那么有什么问题呢?

还有人声称它应该可以工作:Firestore select where is not null

这是我的规则:

service cloud.firestore {
  match /databases/{database}/documents {
    function isSignedIn() {
      return request.auth != null;
    }

    function getRole(rsc) {
      // Read from the "roles" map in the resource (rsc).
      return rsc.data.roles[request.auth.uid];
    }

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

    match /organizations/{organizationId} {
      allow read: if isOneOfRoles(resource, ['owner']);
      allow write: if isOneOfRoles(resource, ['owner']);
    }
  }
}

就像我说的,如果我比较角色是否是所有者,它会起作用,但是如果用户的 uid 存在于角色数组中,我想得到结果,无论她担任什么角色。

【问题讨论】:

    标签: javascript firebase google-cloud-firestore


    【解决方案1】:

    我还发现这部分文档令人困惑(或者更确切地说,缺少非常重要的细节)。 Firestore 安全性要求您遵循有关数据结构的非常具体的设计模式。这是因为 Firebase 安全规则语言在表达规则时的功能比您可以针对数据运行的简单和复合查询表达式要少。

    在尝试保护我的数据库时,我逐渐不得不放弃我最初的数据抽象思想,并从安全语言强加的限制重新开始。我开始应用以下模式,而不是 Firestore 文档 (https://firebase.google.com/docs/firestore/solutions/role-based-access) 中建议的角色表示。您的用例采用的代码。

    {
      "name": "MyAmazingCompany",
      "roles": {
        "anyRole": ["user-id-1", "user-id-2", "user-id-3", "user-id-4"],
        "owners": ["user-id-1"],
        "editors": ["user-id-2"],
        "readers": ["user-id-3", "user-id-4"],
      }
    }
    

    因此,本质上,不同的角色级别是角色对象的属性,属于给定角色的用户存储为角色属性下的 id 数组。还有一个名为anyRole 的附加元角色,它用作方便查询的集合。

    Firebase 安全规则如下:

    rules_version = '2';
    
    service cloud.firestore {
      match /databases/{database}/documents {
            match /organizations/{organization} {
        
          function hasReadPermission(res) {
            let anyRole = request.auth.uid in res.data.accessors.anyRole;
            return anyRole;
          }
          
          function hasWritePermission(res) {
            let owner = request.auth.uid in res.data.accessors.owners;
            let editor = request.auth.uid in res.data.accessors.editors;
            return owner || editor;
          }
    
          allow read: if hasReadPermission(resource);
          allow write: if hasWritePermission(resource);
        }
      }
    }
    

    最后,使用array-contains on roles.anyRole查询数据非常简单

    获取用户有权访问的所有文档:

    organizationsRef.where(`roles.anyRole`, 'array-contains', user.uid);
    

    获取用户拥有的所有文档:

    organizationsRef.where(`roles.owner`, 'array-contains', user.uid);
    

    【讨论】:

      【解决方案2】:

      您的规则的一个问题可能是您检查角色映射的方式。如果您尝试访问不存在的映射键,它将引发异常。

      function getRole(rsc) {
        // Read from the "roles" map in the resource (rsc).
        return rsc.data.roles[request.auth.uid]; // this will throw an exception if the uid isn't in the map
      }
      

      在规则语言中,地图有一个get("key", "default-value") 方法,可以帮助您安全地做您正在做的事情。所以这可能会有所帮助:

      function getRole(rsc) {
        // Read from the "roles" map in the resource (rsc).
        return rsc.data.roles.get(request.auth.uid, null);
      }
      
      function isOneOfRoles(rsc, array) {
        // Determine if the user is one of an array of roles
        return isSignedIn() && getRole(rsc) != null && (getRole(rsc) in array);
      }
      

      我没有在 firebase 中运行您的代码来验证没有其他问题,但这至少是您可能遇到的一个问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-09-04
        • 2019-04-26
        • 2022-07-01
        • 1970-01-01
        • 2021-08-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多