Firebase 安全规则阻止写入 Firebase

Firebase Security Rules Block Writing to Firebase

注:此题打上标签polymer因为Polymer库是用来生成Javascript.

这个问题是关于处理 Firebase 安全性的两个不同但相关的问题。当试图让 Firebase 安全规则起作用时,问题 1 和问题 2 似乎暗示了相反的现实和相反的结果。 (FWIW:Here is my prior unsuccessful attempt to write this question。)

Here is the live code in a JSBin.

http://jsbin.com/hinehoyigo/edit?html,output

问题 1

Firebase 安全规则阻止写入 Firebase

说明

  1. 输入您的 Firebase ID。示例:"hot-sauce-123"
  2. 在新标签页或 window 中,转到您的 firebase 并打开它
  3. 允许匿名身份验证: 你的火力基地 > 登录&授权 > 匿名选项卡 > 检查 "Enable Anonymous User Authentication"
  4. 不应用安全规则:安全与规则 >
    {
          "rules": {
            ".read": true,
            ".write": true
          }
        }
  5. Return返回jsbin
  6. Select "anonymous" 作为身份验证提供者:下拉菜单 > 匿名
  7. 单击标记为 "login"
  8. 的按钮
  9. 验证右侧每个字段的登录状态
  10. 打开您的控制台:Chrome > 查看 > 开发人员 > 开发人员工具
  11. 单击标记为 "Print User to console"
  12. 的按钮
  13. 通过验证打印到控制台的用户对象来仔细检查登录状态
  14. 单击标记为 "Print Firebase to console"
  15. 的按钮
  16. 通过检查输出到控制台的 Firebase URL 验证正确的 firebase
  17. 单击标记为 "Write to Firebase — Plain Url"
  18. 的按钮
  19. 检查你的 Firebase 数据;注意没有写入发生
  20. 单击标记为 "Write to Firebase — .json Url"
  21. 的按钮
  22. 检查你的 Firebase 数据;注意写入成功
  23. 区分两次写入尝试,因为前一次尝试写入 {"quux":"baz"}; 后者尝试写 {"jquux":"jbaz"}
  24. 添加安全规则:安全与规则 >
    {
                "rules": {
                    "users": {
                        "$uid": {
                            ".read": "auth != null && auth.uid === $uid",
                            ".write": "auth != null && auth.uid === $uid"
                        }
                    }
                }
            }
  25. 再次单击标有 "Write to Firebase — .json Url"
  26. 的按钮
  27. 检查你的 Firebase 数据;注意写现在失败
  28. 结论/问题陈述:Firebase 安全规则阻止写入 Firebase。

问题 2

模拟器阻止 .json URL 被使用(如上要求)

说明

  1. 打开你的 Firebase
  2. 验证安全规则是否到位(参见上面问题 #1 中的步骤 #19)...
  3. 打开您的模拟器:垂直导航菜单 > 模拟器
  4. 选中标记为 "Custom Auth"
  5. 的单选按钮
  6. 自定义身份验证输入字段应该是这样的 “{提供者:'anonymous',uid:'ag69g401-f097-4171-bca4-927fd1a6e1f3'}”
  7. 单击标记为 "Authenticate"
  8. 的按钮
  9. 验证标记为 "Custom Auth"
  10. 的单选按钮旁边是否有绿色的小复选标记
  11. 转到第 2 部分
  12. 单击标签为 "Write"
  13. 的选项卡
  14. 在标有 URL 的输入字段中,输入 "users/ag69g401-f097-4171-bca4-927fd1a6e1f3/foo/bar"
  15. 验证您刚刚输入的 URL 路径中的用户 ID,与上述 Custom Auth 字段中的 uid 值相匹配
  16. 单击标记为 "Simulate Write"
  17. 的按钮
  18. 注意响应是这样的:
    尝试用 auth={"provider":"anonymous","uid":"ag69g401-f097-4171-bca4-927fd1a6e1f3"}
    写入 {"key":"value"} to /users/ag69g401-f097-4171-bca4-927fd1a6e1f3/foo/bar
    /
    /users
    /users/ag69g401-f097-4171-bca4-927fd1a6e1f3:.write: "auth != null && auth.uid === $uid"
        => true
    允许写入。
  19. 注意:此结果与上面步骤#14 和#15 的结果相反,其中普通 URL(没有附加 .json)无法写入
  20. 将“.json”附加到 URL 以便输入字段显示为类似 "users/ag69g401-f097-4171-bca4-927fd1a6e1f3/foo/bar.json"
  21. 单击标记为 "Simulate Write"
  22. 的按钮
  23. 注意响应是这样的:
    路径无效。模拟中止。
  24. 注意:此结果与上述步骤 #16 和 #17 的结果相反,其中附加的 .json URL 是唯一有效的;
  25. 请注意,这些模拟器测试表明的结果与上述问题 #1 中的实时代码测试结果相反

问题 1

您正在使用 Polymer firebase-auth 元素通过 Firebase 进行身份验证。

<firebase-auth id="firebaseLogin"
               user="{{user}}"
...

在引擎盖下,这调用了 Firebase.authAnonymously() method, which authenticates the current session in the Firebase JavaScript SDK

您正在使用以下方式写入 Firebase:

computeFbTargetJson: function(f) {
    return f + '.json';
}

this.set('$.ajax.url'  , this.fbTargetJson);
this.set('$.ajax.body' , JSON.stringify({
    jquux: 'jbaz'
   }));
this.$.ajax.generateRequest();

这是向 Firebase 发出 AJAX 请求,这意味着您正在使用 Firebase's REST API。但由于这是一个常规的 HTTP 调用,它不会 "inherit" 然后从 Firebase JavaScript 客户端进行身份验证。

要验证您的 REST 请求,您需要 pass in an auth parameter as documented in the Firebase documentation。您可以使用 ref.getAuth().token.

从 Firebase 参考中获取令牌

问题 2

您的 Firebase 数据库中的每个元素都可以通过唯一的 URL 访问。您可以使用 Firebase SDK 之一访问它,也可以直接访问 Firebase 公开的 REST API。

根据我从 jsbin 中收集到的信息,您正在使用以下方式写入 Firebase:

computeFbTargetJson: function(f) {
    return f + '.json';
}

this.set('$.ajax.url'  , this.fbTargetJson);
this.set('$.ajax.body' , JSON.stringify({
    jquux: 'jbaz'
   }));
this.$.ajax.generateRequest();

这是向 Firebase 发出 AJAX 请求,这意味着您正在使用 Firebase's REST API。该 API 文档的第一段解释了 Firebase 数据库 URLs 如何映射到 REST API:

We can use any Firebase app URL as a REST endpoint. All we need to do is append .json to the end of the URL and send a request from our favorite HTTPS client.

因此,为了使用 REST API 访问 Firebase 中的任何数据,您将 .json 附加到该数据的 URL。

当您使用 Firebase 模拟器时,操作类似于使用 Firebase 的 JavaScript SDK。在这种情况下,您不应将 .json 后缀放在 URL.

的末尾

假设您在 https://mine.firebaseio.com/ 有一个 Firebase 数据库,假设您在 /users/de01fc8104 有一个用户配置文件。

  • 您可以在模拟器中或使用 Firebase SDK 作为 https://mine.firebaseio.com/users/de01fc8104
  • 访问该记录
  • 要使用 REST API 访问记录,URL 是 https://mine.firebaseio.com/users/de01fc8104.json

总结

这两个问题都是由于您使用两种不同的方式访问 Firebase 造成的:JavaScript SDK 和 REST API。虽然这两种方法可以一起使用,但您必须确保提供所需的信息。一般来说,如果您坚持使用一种从单个客户端访问 Firebase 的方式,您将获得更轻松的体验。

在聚合物语言中翻译成:

Use the <firebase-collection> element's .add() method 在执行安全规则时从客户端向 Firebase 写入数据。从代码的角度来看,它更高效,因为 firebase-collection 会自动为您处理所有必要的身份验证令牌。