这是我的数据库结构
"tasks"
"$taskId"
...
"user": "firebase user id"
我已经在$taskId
下写了一个规则".read": data.child('user').val() === auth.uid"
.当我尝试访问单个任务时,此规则正在生效。
这是否也能保证如果我编写像firebase.database().ref('/tasks').orderByChild('status').limitToFirst(1)
这样的查询,我只会获得用户 id 字段为auth.uid
的任务。或者我也应该在tasks
下写一个.read
条款
您的问题有几个方面需要回答:
1/您应该在哪个级别编写安全规则?
如果仅在task
级别编写,如下所示,则无法查询整个任务集。
您可以通过执行以下操作来测试它:
规则:
{
"rules": {
"tasks": {
"$taskID": {
".read": "auth != null",
".write": "auth != null"
}
}
}
}
.JS:
var db = firebase.database();
var ref = db.ref('tasks');
firebase.auth().signInWithEmailAndPassword("....", "....")
.then(function(userCredential) {
ref.once('value').then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
console.log(childSnapshot.val());
});
});
});
此操作将失败,并显示"错误:permission_denied/tasks:客户端无权访问所需数据"。
如果将var ref = db.ref('tasks');
更改为 varref = db.ref('tasks/123456');
(123456是现有任务 ID(,您将获得结果。
如果将规则更改为以下内容,则前两个查询将起作用。
{
"rules": {
"tasks": {
".read": "auth != null",
".write": "auth != null"
}
}
}
2/您应该如何仅获取用户 id 字段为 auth.uid 的任务?
首先要注意的是"规则不是过滤器",详见:https://firebase.google.com/docs/database/security/securing-data#rules_are_not_filters
因此,如果您按如下方式实施安全规则:
{
"rules": {
"tasks": {
"$taskId": {
".read": "auth != null && data.child('user').val() === auth.uid",
".write": "auth != null"
}
}
}
}
您需要编写一个查询,其中包含对用户 uid 的相同限制,如下所示:
var db = firebase.database();
firebase.auth().signInWithEmailAndPassword("....", "....")
.then(function(userCredential) {
var ref = db.ref('tasks').orderByChild('user').equalTo(userCredential.user.uid);
ref.once('value').then(function(snapshot) {
snapshot.forEach(function(childSnapshot) {
console.log(childSnapshot.val());
});
});
});
但此查询将不起作用,再次,因为"错误:permission_denied/tasks:客户端无权访问所需数据。
您不能执行以下操作,因为"较浅的安全规则会覆盖更深路径上的规则"。
{
"rules": {
"tasks": {
".read": "auth != null",
".write": "auth != null"
"$taskId": {
".read": "auth != null && data.child('user').val() === auth.uid",
".write": "auth != null"
}
}
}
}
一种解决方案是使用基于查询的规则(请参阅此处的文档(并按如下方式编写规则:
{
"rules": {
"tasks": {
".read": "auth != null &&
query.orderByChild == 'user' &&
query.equalTo == auth.uid",
".write": "auth != null"
}
}
}
但是,您可能已经注意到,这将阻止您按user
以外的其他内容(例如按status
(对查询进行排序(并对其进行过滤(,因为"您一次只能使用一种排序方法。
因此,解决方案是创建与现有结构并行的第二个数据结构,在其中将用户添加为顶部节点,例如
"tasks"
"$taskId"
...
"user": "firebase user id"
"tasksByUser"
"$userId"
"$taskId"
...
您将使用 update(( 方法同时写入两个数据结构。请参阅此处的文档。
我在tasks
下给出了.read: true
,它在返回结果之前正在考虑在各个任务对象下编写的规则。