【问题标题】:Let client create user but not modify untill authenticated让客户端创建用户但不修改直到通过身份验证
【发布时间】:2014-08-30 14:37:37
【问题描述】:

我正在使用 roder 中的主干.js 编写一个应用程序来学习。你可以在这里找到我实际得到的:https://the-todo-app.firebaseapp.com/

我的想法是允许人们使用 simpleLogin 和 facebook 在应用程序中注册以创建用户,然后他们被重定向到他们的用户并被允许创建和修改他们的待办事项,但我遇到的问题是实际上每个用户都有可以在用户文件夹上写入,这意味着他们可以输入、删除或修改其他用户的数据。我想限制 firebase 的安全性,以允许他们根据他们的 id 创建用户,但如果他们没有经过身份验证,则不允许他们写。这是我实际拥有的:

{
  "rules": {
    ".read": true,
    ".write": true,
    ".validate": "data.hasChildren(['name', 'picture'])",
    "users": {
      "$user": {
        ".read": "$user == auth.id",
        ".write": "$user == auth.id"
      }          
    }
  }
}

阿苏试过这个:

{
  "rules": {
    ".read": true,
    "users": {
      "$user": {
        ".read": "$user == auth.id",
        ".write": "$user == auth.id"
      }          
    }
  }
}

但这种方法不允许客户端创建用户 ID。

这是我的数据的实际外观:

{
  "users" : {
    "10152111176005069" : {
      "name" : "Jhonnatan Gonzalez Rodriguez",
      "picture" : "url to pic"
    },
    "10154397958535078" : {
      "name" : "Diana Rincón P",
      "picture" : "url to pic"
    },
    "10152167159946759" : {
      "name" : "Sebastian Ayala",
      "picture" : "url to pic"
    }
  },
  "title" : "The todo app"
}

如果你们知道如何做到这一点,我将不胜感激。

根据 ArneHugo 的回答,我刚刚设置了这个规则,并且看起来效果很好,我需要做更多的测试才能确定。

{
  "rules": {
    "users": {
      ".write": "!data.child(auth.id).exists()",
      "$user": {
        ".read": "$user == auth.id",
        ".write": "$user == auth.id",
        ".validate": "newData.hasChildren(['name', 'picture'])"
      }          
    }
  }  
}

我实际上必须将用户的 .read 规则添加到 true 以允许他们检查数据是否存在,这就是规则现在的样子。

{
  "rules": {
    "users": {
      ".read": "true",
      ".write": "!data.child(auth.id).exists()",
      "$user": {
        ".read": "$user == auth.id",
        ".write": "$user == auth.id",
        ".validate": "newData.hasChildren(['name', 'picture'])"
      }          
    }
  }  
}

这就是输出查找匿名用户的方式

Attempt to write {"id":"6726363"} to /users/6726363 with auth=null
    /
    /users:.write: "!data.child(auth.id).exists()"
5:30: child() expects a string argument.
        => false
    /users/6726363:.write: "$user == auth.id"
        => false
    /users/6726363:.validate: "newData.hasChildren(['name', 'picture'])"
        => false

Validation failed.
Write was denied.

这就是寻找经过身份验证的用户的方式。

Attempt to write {"name":"6726363","picture":"fb picture"} to /users/6726363 with auth={"id":"6726363"}
    /
    /users:.write: "!data.child(auth.id).exists()"
        => true
    /users/6726363:.validate: "newData.hasChildren(['name', 'picture'])"
        => true
    /users/6726363:.validate: "newData.hasChildren(['name', 'picture'])"
        => true

Write was allowed.

这是匿名尝试写入另一个用户数据的 uoutput。

Attempt to write {"name":"6726363","picture":"fb picture"} to /users/10152111176005069 with auth=null
    /
    /users:.write: "!data.child(auth.id).exists()"
5:30: child() expects a string argument.
        => false
    /users/10152111176005069:.write: "$user == auth.id"
        => false
    /users/10152111176005069:.validate: "newData.hasChildren(['name', 'picture'])"
        => true

No .write rule allowed the operation.
Write was denied.

现在,做这个例子发现一个在数据库中已经存在 id 的经过身份验证的用户可以像这样写入另一个用户的数据。

Attempt to write {"name":"6726363","picture":"fb picture"} to /users/10152111176005069 with auth={"id":"6726363"}
    /
    /users:.write: "!data.child(auth.id).exists()"
        => true
    /users/10152111176005069:.validate: "newData.hasChildren(['name', 'picture'])"
        => true
    /users/10152111176005069:.validate: "newData.hasChildren(['name', 'picture'])"
        => true

Write was allowed.

【问题讨论】:

  • 你看过anonymous auth吗?这可能是比不安全且可能是 hacky 的写入规则更好的解决方案。
  • @Kato 我认为问题在于,如果我设置匿名身份验证,用户将在顶层拥有写入权限,这意味着每个经过身份验证的用户都可以在用户/路径,因为已经过身份验证....我无法为此设置嵌套安全规则这一事实遇到了很大的问题
  • 安全规则级联。如果您允许在 root 下写入,则用户可以在 root 下的任何级别写入。如果您想将它们限制在自己的路径中,请删除根目录下的规则。
  • @Kato 但如果我在用户未注册的情况下删除顶层的 wrtie,它将无法在数据库上创建其 uder:/
  • 根级别的写入权限允许任何用户在不登录的情况下编辑任何数据。使用不同的解决方案。用户通常需要在编写新配置文件之前使用 createUser() 和 login() 创建身份验证令牌。

标签: javascript backbone.js firebase firebase-security firebasesimplelogin


【解决方案1】:

你想做的事是完全可能的,我不同意加藤你应该使用不同类型的登录。

这就是你所需要的:

  "rules": {
    "users": {
      //".write": "!data.exists()", /* Edit: removed, as it always returned false */
      "$user": {
        ".read": "$user == auth.id",
        ".write": "$user == auth.id",
        ".validate": "newData.hasChildren(['name', 'picture'])"
      }          
    }
  }
  1. 新用户可以为自己添加 $user 条目。
  2. 除了自己的用户之外,没有用户可以读取 $user 的内容。
  3. 任何用户都不能向自己以外的 $user 写入数据(包括他们最初创建 $user 时,以确保条目有效)。
  4. $user 条目必须有名称和图片。 (请注意,我移动了您的验证规则。)

Protip:使用 Firebase 中的模拟器测试安全规则。这是一个伟大而简单的工具。

编辑

我做了一个测试,看看你是否真的需要一个读取规则来检查数据是否存在。 (答案:你没有。)

具有以下安全规则

"test": {
    ".write": "!data.child(auth.id).exists()",
    "$user": {
        ".validate": "newData.hasChildren(['name', 'picture']) && $user == auth.id",
        ".read": "$user == auth.id",
        ".write": "$user == auth.id"
    }          
}

试图写一个新用户:

Attempt to write {"name":"Beardinator","picture":"i.imgur.com/axXz9sr.jpg"} to /test/1337 with auth={"id":"1337"}
    /:.write: "root.child('adminPanel').child('admins').child(auth.uid).val() != null"
20:67: child() expects a string argument.
        => false
    /test:.write: "!data.child(auth.id).exists()"
        => true
    /test/1337:.validate: "newData.hasChildren(['name', 'picture']) && $user == auth.id"
        => true
    /test/1337:.validate: "newData.hasChildren(['name', 'picture']) && $user == auth.id"
        => true

Write was allowed.

在我的测试中,如果没有关于“用户”的 .read 规则,我可以检查数据是否存在。

【讨论】:

  • 您好,我实际上是在模拟器中测试的,但是“.write”:“!data.exists()”规则不允许我创建新用户,即使用户已通过身份验证跨度>
  • 我编辑了这个问题,向您展示根据您的答案设置的规则实际上是如何运作的。
  • "!data.exists()" 每次都返回 false,所以我删除了它。但是写作仍然对我有用。尝试编写新用户时,能否显示在模拟器中得到的输出?
  • 嘿,我添加了您要求的详细信息。我实际上发现该方法有一个错误:(
  • 嘿,请删除“用户”中的 .write 规则。另一个写入规则,“$user”中的规则足以允许您想要的内容,仅此而已。 (此外,您现在拥有的写入规则是错误的,它允许用户更改 any 用户,只要她自己还没有添加到数据库中。这不是你想要的。但正如我所说只需删除 .write 规则,它应该可以正常工作。)
猜你喜欢
  • 2012-04-25
  • 1970-01-01
  • 1970-01-01
  • 2020-12-16
  • 2021-01-25
  • 2016-07-09
  • 1970-01-01
  • 1970-01-01
  • 2014-03-31
相关资源
最近更新 更多