仅读取具有值为 auth.uid 的字段的列表的子项



这是我的数据库结构

"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,它在返回结果之前正在考虑在各个任务对象下编写的规则。

最新更新