Firebase对象所有权与事件观察
我在iOS应用中使用了Firebase。 我希望每个对象都有一个creatorId
属性,其值是通过身份validation的用户标识(具有Firebase身份validation对象的authData.uid
)。 我正在使用自定义令牌生成器进行身份validation,但是问题也可以通过匿名login进行复制。
我希望用户只能阅读(和写,但让我们专注于阅读,因为这是我有我的问题)他们创build的对象。 换句话说,查询用户的authentication用户ID将匹配他们正在提取的对象的creatorId
。
当我制作查询和规则来实现这一点时,我遇到了权限问题。
这里是规则和安全的Firebase文档。
以下是我的Firebase仪表板对于Task
对象的外观:
+ firebase-base + tasks + {task_id} + creatorId: + title:
其中task_id
是插入时由Firebase生成的唯一标识符。
我的规则看起来像这样(现在让我们忽略编写规则):
{ "rules": { "tasks": { "$task_id": { ".read": "auth.uid === data.child('creatorId').val()" } } } }
读取一个特定的任务工作正常,但我希望能够使用observeEventType
和相关函数进行查询,说:“获取所有我创build的任务”。 这对我不起作用。 我得到“权限被拒绝”的错误。
下面是我在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. }
根据@ Ymmanuel的build议,我也试过在我的查询中更具体,就像这样:
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. }
这些块都没有工作,我总是得到“权限被拒绝”的错误。 我究竟做错了什么?
你所缺less的是,你假设安全规则是查询,这是不正确的。
检查链接中的“规则不过滤”部分。
安全规则只会validation您是否可以读取或写入Firebase数据库的特定path。
如果您只想接收特定用户的更改,则应使用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. }
通过这种方式,您可以获得与用户相关的所有事件,并通过应用安全规则来保护信息。
同样,如果你只想让创build者自己写任务,你也应该考虑创build任务的情况,写下如下的内容:
"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", } }
(检查语法,但这是一般的想法)
几个意见:
如果本地持续打开,并且没有互联网连接,并且没有本地值,则不会调用任何块。
问题中的观察代码正在扰乱我,这是没有错的,但如果是这样的话可能会更清楚一点:
reference.observeEventType(.ChildChanged, withBlock: { snapshot in print(snapshot.value) }, withCancelBlock: { error in print(error.description) })
编辑:
现在的问题更清楚了
我想让用户只能读取他们创build的对象。
我将通过以下演示:
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
以及允许用户只从他们创build的post节点读取的规则
"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" } } }
然后代码来testing。 我们假设当前用户的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子项指示的后创build的uid_0。
例如,如果将path更改为posts / posts_1(或其他任何内容),则读取被拒绝。
这个答案我不是直接回答这个问题,就好像你期待的规则是'阻止'或'过滤'结果数据,这不是什么规则(每个其他答案)。
所以你可能想通过构build一个查询来拉出你想要工作的post的基础上像这样created_by = auth.uid不同的path
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) })