我在iOS应用中使用Firebase。我希望每个对象都有一个creatorId
属性,其值是经过身份验证的用户ID(authData.uid
,带有Firebase身份验证对象)。我正在使用自定义令牌生成器进行身份验证,但也可以使用匿名登录重现该问题。
我希望用户只能阅读(和写,但我们现在专注于阅读,因为那是我遇到问题的地方)他们创建的对象。换句话说,查询用户的经过身份验证的用户ID将与他们提取的对象的creatorId
匹配。
当我制作查询和规则以实现此目的时,我遇到了权限问题。
Here是规则和安全的Firebase文档。
以下是Task
对象的Firebase信息中心的外观:
+ firebase-base
+ tasks
+ {task_id}
+ creatorId:
+ title:
其中task_id
是Firebase在插入时生成的唯一标识符。
我的规则看起来像这样(再次,让我们暂时忽略编写规则):
{
"rules": {
"tasks": {
"$task_id": {
".read": "auth.uid === data.child('creatorId').val()"
}
}
}
}
阅读特定任务可以正常工作,但我希望能够使用observeEventType
和相关函数进行查询,“获取我创建的所有任务”。这对我不起作用。我收到“Permission Denied”错误。
以下是我在Swift中的观察方式:
let reference = Firebase(url: "https://{My-Firebase-Base-Reference}/tasks")
reference.observeEventType(.ChildChanged,
withBlock: { (snapshot: FDataSnapshot!) -> Void in
// Success
}) { (error: NSError!) in
// Error: I get Permissions Denied here.
}
Per @ Ymmanuel的建议,我也尝试在我的查询中更具体,如下:
let reference = Firebase(url: "https://{My-Firebase-Base-Reference}/tasks")
reference.queryOrderedByChild("creatorId").queryEqualTo({USER_UID}).observeEventType(.ChildChanged,
withBlock: { (snapshot: FDataSnapshot!) -> Void in
// Success
}) { (error: NSError!) in
// Error: I get Permissions Denied here.
}
这些块都不起作用,我总是得到“Permission Denied”错误。我做错了什么?
答案 0 :(得分:3)
您缺少的是您假设安全规则是查询而不是真实。
检查 链接中的Rules are Not Filters部分。
安全规则仅验证您是否可以读取或写入firebase数据库的特定路径。
如果您只想接收特定用户的更改,则应使用firebase查询。
例如,如果您想获得特定用户的所有任务,您应该这样做:
let reference = Firebase(url: "https://{My-Firebase-Base-Reference}/tasks")
reference.queryOrderedByChild("creatorId").queryEqualTo(YOUR_CURRENT_USER_UID).observeEventType(.ChildChanged,
withBlock: { (snapshot: FDataSnapshot!) -> Void in
// Success
}) { (error: NSError!) in
// Error: Get Permissions Denied Here.
}
通过这种方式,您可以获取仅与您的用户相关的所有事件,并通过应用安全规则来保护信息。
如果您只想让创建者编写自己的任务,您还应该考虑创建任务的情况并编写如下内容:
"tasks": {
//You need to include the $task_id otherwise the rule will seek the creatorId child inside task and not inside your auto-generated task
"$task_id": {
".read": "auth.uid === data.child('creatorId').val()",
//this is to validate that if you are creating a task it must have your own uid in the creatorId field and that you can only edit tasks that are yours...
".write":"(newData.child('creatorId').val() === auth.uid && !data.exists()) || (data.child('creatorId').val() === auth.uid && data.exists())",
//you should add the index on to tell firebase this is a query index so your queries can be efficient even with larger amounts of children
".indexOn":"creatorId",
}
}
(检查语法,但这是一般的想法)
答案 1 :(得分:1)
几条评论:
如果启用了本地持久性,并且您没有互联网连接并且没有本地值,则不会调用任何块。
问题中的观察代码是在困扰我,这没有错,但如果它是这样的话可能会更清楚:
reference.observeEventType(.ChildChanged, withBlock: { snapshot in
print(snapshot.value)
}, withCancelBlock: { error in
print(error.description)
})
编辑:
现在问题更清楚了
我希望用户只能阅读他们创建的对象。
我将通过以下内容进行演示:
Firebase结构:
posts
post_0
created_by: uid_0
msg: some message
post_1
created_by: uid_1
msg: another message
post_2
created_by: uid_2
msg: yippee
以及允许用户仅从他们创建的帖子节点读取的规则
"rules": {
".read": false,
".write": false,
"posts": {
".read": false,
"$post_id": {
".read": "root.child('posts').child($post_id).child('created_by').val() == auth.uid",
".write": "auth != null"
}
}
}
然后是要测试的代码。我们假设当前用户uid是uid_0:
let reference = self.myRootRef.childByAppendingPath("posts/post_0")
reference.observeEventType(.ChildAdded, withBlock: { snapshot in
print(snapshot.value)
}, withCancelBlock: { error in
print(error.description)
})
上面的代码将允许从节点post_0读取,该节点是由created_by子节点指示创建的post uid_0。
例如,如果路径更改为posts / posts_1(或其他任何内容),则拒绝读取。
这个答案我没有直接回答这个问题,好像你期望规则“阻止”或“过滤”结果数据,而不是规则(根据其他答案)。
因此,您可能希望通过构建查询来根据created_by = auth.uid(例如
)提取您想要使用的帖子,从而走另一条道路。let reference = self.myRootRef.childByAppendingPath("posts")
reference.queryOrderedByChild("created_by").queryEqualToValue("uid_1")
.observeEventType(.Value, withBlock: { snapshot in
print(snapshot.value)
}, withCancelBlock: { error in
print(error.description)
})