适用于层次结构的Firebase安全规则

时间:2016-09-17 06:36:37

标签: firebase firebase-realtime-database

如何让用户访问层次结构中某个节点以下的任何数据,并且可以轻松查询?这可以在Firebase中完成,还是我不得不放弃我心爱的Firebase并回到...抱怨...抱怨...... RDBMS?

我尝试了两种不同的方式。一个可以轻松查询,但很难限制访问。另一个使得更容易限制访问,但意味着我必须做嵌套循环来聚合我的所有数据。

具体来说,我有一个典型的商业组织:

  • 公司
    • 西部地区
      • 第1分部
        • 部门1
        • 部门2
      • 第2分部
        • 部门3
        • 部门4
    • 南部地区
      • 第3分部
        • 部门5
        • 部门6
  • 公司2 ...等

在最低(部门)级别,我的订单的金额必须汇总。

首次尝试

数据(非规范化)

{
    "Orders": {
        "UniqueID1": {
            "company": "Company",
            "region": "West Region",
            "division": "Division 1",
            "department": "Department 1",
            "amount": 19.8
        },
        "UniqueID2": {
            "company": "Company",
            "region": "West Region",
            "division": "Division 1",
            "department": "Department 1",
            "amount": 20.1
        },
        ...and so on.
    },
    "Users": {
        "Bob's UID": {
            "departments": {
                "Department 1": true, // Note that these two departments combined are Division 1
                "Department 2": true
            }
        }
    }
}

规则

{
    "Orders": {
        ".indexOn": ["company", "region", "division", "department"],
        ".read":false,
        ".write":false,
        "$order_id": {
            ".read": "root.child('Users').child(auth.uid).child('departments').hasChild(data.child('department').val())"
        }
    }
}

结论

赞成

  • 查询非常灵活,例如:ordersRef.orderByChild('division').equalTo('Division 1')
  • 查询很快。对于200k记录,这可以在2秒内完成。

缺点

  • 我不相信我可以通过某种结构来限制访问。我根据上面的规则得到permission_denied。我认为这是因为我遇到了问题"规则不是过滤器,tsk tsk tsk"。

第二次尝试

数据(更加规范化)

{
    "Orders": {
        "Department 1": {
            "UniqueID1": {
                "company": "Company",
                "region": "West Region",
                "division": "Division 1",
                "amount": 19.8
            },
            "UniqueID2": {
                "company": "Company",
                "region": "West Region",
                "division": "Division 1",
                "amount": 20.1
            },
        },
        "Department 2": {...
        ...and so on.
    },
    "Users": {
        "Bob's UID": {
            "departments": {
                "Department 1": true, // Note that these two departments combined are Division 1
                "Department 2": true
            }
        }
    }
}

规则

{
    "Orders": {
        ".read":false,
        ".write":false,
        "$order_id": {
            ".read": "root.child('Users').child(auth.uid).child('departments').hasChild(data.child('department').val())"
        }
    }
}

结论

赞成

  • 我现在可以通过一次阅读一个部门来限制使用安全规则的访问。

缺点

  • 我不认为我可以对" Orders / $ order_id /"进行深度和变量索引。 +公司,地区或部门,这意味着我必须单独调用每个部门的订单,以便在更高的级别汇总。

1 个答案:

答案 0 :(得分:1)

您的第一个数据结构看起来很合理。您可以访问您有权访问的特定订单,并且您已经可以找到特定用户的部门列表。

要允许访问(例如)分部的订单,您还需要添加将分部映射到订单ID列表的辅助索引:

{
    "Orders": {
        "UniqueID1": {
            "company": "Company",
            "region": "West Region",
            "division": "Division 1",
            "department": "Department 1",
            "amount": 19.8
        },
        "UniqueID2": {
            "company": "Company",
            "region": "West Region",
            "division": "Division 1",
            "department": "Department 1",
            "amount": 20.1
        },
        ...and so on.
    },
    "Users": {
        "Bob's UID": {
            "departments": {
                "Department 1": true, // Note that these two departments combined are Division 1
                "Department 2": true
            }
        }
    },
    "OrdersByDivision": {
        "Division 1": {
            "UniqueID1": true,
            "UniqueID2": true
        }
    }
}

现在,您可以在OrdersByDivision下找到方向查找的分部列表,然后循环加载订单:

ref.child('OrdersByDivision/Division 1').on('child_added', function(snapshot) {
    ref.child('Orders').child(snapshot.key).once('value', function(order) {
        console.log(order.val());
    });
});

大多数没有使用Firebase进行Web开发的开发人员担心这种模式会很慢。但鉴于Firebase通过已建立的连接检索项目,实际上这非常快。见Speed up fetching posts for my social network app by using query instead of observing a single event repeatedly