3

I am building a simple Firebase application with AngularJS. This app authenticates users through Google. Each user has a list of books. Anyone can see books, even if they are not authenticated. Only the creator of a book can edit it. However, individual users need to be able to record that they've read a book even if someone else added it.

I have rules.json like so:

{
  "rules": {
    ".read": false,
    ".write": false,
    "book": {
      "$uid": {
        ".write": "auth !== null && auth.uid === $uid",
      }
      ".read": true,
    }
  }
}

And I am trying to write a book simply with:

$firebaseArray(new Firebase(URL + "/book")).$add({foo: "bar"})

I get a "permission denied" error when trying to do this although I do seem to be able to read books I create manually in Forge.

I also think that the best way to store readers would be to make it a property of the book (a set of $uid for logged-in readers). ".write" seems like it would block this, so how would I do that?

"$uid": {
  ".write": "auth !== null && auth.uid === $uid",
  "readers": {
    ".write": "auth !== null"
  }
},

It seems like a validation rule would be appropriate here as well ... something like newData.val() == auth.uid, but I'm not sure how to validate that readers is supposed to be an array (or specifically a set) of these values.

4

2 回答 2

7

让我们从一个示例 JSON 片段开始:

  "book": {
    "-JRHTHaIs-jNPLXOQivY": { //this is the generated unique id
      "title": "Structuring Data",
      "url": "https://www.firebase.com/docs/web/guide/structuring-data.html",
      "creator": "twiter:4916627"

    },
    "-JRHTHaKuITFIhnj02kE": {
      "title": "Securing Your Data",
      "url": "https://www.firebase.com/docs/security/guide/securing-data.html",
      "creator": "twiter:209103"
    }
  }

所以这是一个包含两个文章链接的列表。每个链接都是由不同的用户添加的,该用户由 标识creator。的值为creatora uid,这是 Firebase 身份验证提供的值,可在您的安全规则下的auth.uid.

我将在这里将您的规则分为两部分:

{
  "rules": {
    ".read": false,
    "book": {
      ".read": true,
    }
  }
}

据我所知,您的.read规则是正确的,因为您的 ref 是 /book 节点。

$firebaseArray(new Firebase(URL + "/book"))

请注意,下面的 ref 不起作用,因为您没有对顶级节点的读取权限。

$firebaseArray(new Firebase(URL))

现在是.write规则。首先,您需要已经授予用户对该book级别的写访问权限。调用$add意味着您要在该级别下添加一个节点,因此需要写入访问权限。

{
  "rules": {
    "book": {
      ".write": "auth != null"
    }
  }
}

为了清楚起见,我将.read规则留在这里。

这允许任何经过身份验证的用户写入书节点。这意味着他们可以添加新书(您想要的)和更改现有的书(您不想要的)。

你的最后一个要求是最棘手的。任何用户都可以添加一本书。但是一旦有人添加了一本书,只有那个人可以修改它。在 Firebase 的安全规则中,您可以这样建模:

{
  "rules": {
    "book": {
      ".write": "auth != null",
      "$bookid": {
        ".write": "!data.exists() || auth.uid == data.child('creator').val()"
      }
    }
  }
}

在最后一条规则中,如果该位置没有当前数据(即它是一本新书)或者如果数据是由当前用户创建的则我们允许编写特定的书。

在上面的例子$bookid中只是一个变量名。重要的是,它的规则适用于每一本书。如果需要,我们可以$bookid在我们的规则中使用它,它会分别保持-JRHTHaIs-jNPLXOQivY-JRHTHaKuITFIhnj02kE。但在这种情况下,这不是必需的。

于 2015-06-16T14:49:20.313 回答
2

首先是“权限被拒绝”错误。您收到此错误是因为您尝试直接在“book”节点而不是“book/$uid”中写入。

您现在所做的示例:

  "book": {
    "-JRHTHaIs-jNPLXOQivY": { //this is the generated unique id
      "foo": "bar"
    },
    "-JRHTHaKuITFIhnj02kE": {
      "foo": "bar"
    }
  }

在您的规则中,您将写入的全局规则设置为 false,因此这将是默认值,并且您已经为特定节点 book/$uid 制定了规则。因此,当尝试直接在“book”中写入时,它将采用设置为 false 的默认规则。查看保护您的数据以获取有关 Firebase 规则的更多信息。

对于您问题的最后一部分,我建议您查看结构化数据,以获取有关在 Firebase 中构建数据的最佳方法的更多信息。

因此,请仔细查看您希望在 firebase 中保存和写入的内容和方式,并确保您的规则结构相应。

于 2015-06-16T11:48:23.603 回答