这是我的数据库结构
"tasks"
"$taskId"
...
"user": "firebase user id"
我已在".read": data.child('user').val() === auth.uid"
下编写了一条规则$taskId
。当我尝试访问单个任务时,此规则将生效。
这也可以保证,如果我编写firebase.database().ref('/tasks').orderByChild('status').limitToFirst(1)
之类的查询,我只会获得用户ID字段为auth.uid
的任务。或者我还应该在.read
tasks
条款
答案 0 :(得分:2)
您的问题有几个方面需要回答:
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());
});
});
});
这将失败,并显示“错误:来自/ tasks的permission_denied:客户端无权访问所需数据。”
如果您将var ref = db.ref('tasks');
更改为var ref = 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());
});
});
});
但是,此查询将无效,因为“错误:在/ tasks中的permission_denied:客户端无权访问所需数据。”
您既不能执行以下操作,因为“较浅的安全规则会覆盖较深路径的规则。”:
{
"rules": {
"tasks": {
".read": "auth != null",
".write": "auth != null"
"$taskId": {
".read": "auth != null && data.child('user').val() === auth.uid",
".write": "auth != null"
}
}
}
}
一种解决方案是使用基于查询的规则(请参阅文档here)并按如下方式编写规则:
{
"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()方法同时写入两个数据结构。请参阅文档here。
答案 1 :(得分:0)
我在.read: true
下提供tasks
,并且在返回结果之前正在考虑在各个任务对象下编写的规则。