【问题标题】:Verifying an anonymous user's display name in Firebase realtime database rules在 Firebase 实时数据库规则中验证匿名用户的显示名称
【发布时间】:2018-07-12 07:39:19
【问题描述】:

我正在为匿名用户设置一个显示名称,并希望确保新值与此设置的显示名称相匹配。以下规则失败:

"name": { ".validate": "newData.val() == auth.token.name" }

这是为什么? docs 表示显示名称存储在auth.token.name 中。

以下是我的 Firebase 规则的完整副本:

{
    "rules": {
    ".read": false,
    ".write": false,
    "messages": {
        ".read": true,
        "$message": {
            ".write": "auth != null",
            ".validate": "newData.hasChildren(['createdAt', 'text', 'user'])",

            "createdAt": { ".validate": "newData.val() == now" },
            "text": { ".validate": "newData.isString() && newData.val().length > 0" },
            "user": {
                ".validate": "newData.hasChildren(['_id', 'name'])",
                 "_id": { ".validate": "newData.val() == auth.uid" },
                 "name": { ".validate": "newData.val() == auth.token.name" },
            "$other": { ".validate": false }
        },
        "$other": { ".validate": false }
      }
    }
  }
}

【问题讨论】:

  • 请发布您的完整安全规则 JSON
  • @RosárioPereiraFernandes 刚刚发布了它们。当我将 user.name 规则切换为仅验证 newData.isString() 时,我确认写入工作
  • 您确定可以按照当前规则进行读写吗?因为根据the documentation:“较浅的安全规则覆盖较深路径的规则。子规则只能授予父节点已经声明的额外权限。它们不能撤销读取或写入权限。”。而且我看到您拒绝在根节点中进行读写。所以任何读或写都应该返回一个权限被拒绝的错误。º
  • 它工作,因为模拟器读/写通过,我可以从我的应用程序中获取数据。我相信这意味着子规则不能撤销访问权限,但他们可以授予访问权限。我在模拟器中使用这个测试payload:{ "createdAt": { ".sv": "timestamp" }, "text": "Test 1", "user": { "_id": "48c83bf9-7354-4720-838f-8b68e0addd51", "name": "Mike", } }

标签: firebase firebase-realtime-database firebase-authentication firebase-security


【解决方案1】:

正如我在 cmets 中提到的(取自 the documentation):

较浅的安全规则会覆盖较深路径的规则。子规则 只能授予父节点已经拥有的额外权限 宣布。他们不能撤销读取或写入权限。

这意味着您将无法写入数据库,因为您已在数据库的根节点处声明了.write:false。您可能希望删除该行以具有如下结构:

{
    "rules": {
    ".read": false,
    "messages": {
        ".read": true,
        "$message": {
            ".write": "auth != null",
            ".validate": "newData.hasChildren(['createdAt', 'text', 'user'])",

            "createdAt": { ".validate": "newData.val() == now" },
            "text": { ".validate": "newData.isString() && newData.val().length > 0" },
            "user": {
                ".validate": "newData.hasChildren(['_id', 'name'])",
                 "_id": { ".validate": "newData.val() == auth.uid" },
                 "name": { ".validate": "newData.val() == auth.token.name" },
            "$other": { ".validate": false }
        },
        "$other": { ".validate": false }
      }
    }
  }
}

显示名称确实存储在auth.token.name 变量下。但是,当您在规则模拟器上使用默认的“匿名身份验证”时,这会发送一个带有此默认身份验证负载的请求:

{
  "provider": "anonymous",
  "uid": "N4EbtSX5HbM9JLjsW6hWT3NWzAx1"
}

请注意,在此负载下没有指定 name,因此,auth.token.name 变量为 null,安全规则拒绝写入。

您可以在模拟器上使用您的自定义负载,只需将身份验证提供程序从“匿名”更改为“自定义”,它允许您编辑负载,因此您可以改用这个:

{
  "provider": "anonymous",
  "uid": "N4EbtSX5HbM9JLjsW6hWT3NWzAx1",
  "token":{
    "name": "Mike"
  }
}

使用此身份验证负载,您在 cmets 中提供的数据负载应该可以工作:

{ 
    "createdAt": { 
        ".sv": "timestamp" 
    }, 
    "text": "Test 1", 
    "user": 
    { 
        "_id": "48c83bf9-7354-4720-838f-8b68e0addd51", 
        "name": "Mike"
    }
}

【讨论】:

  • 我以前的规则是有效的,但我会看看这些变化。但是太糟糕了,匿名帐户不包含设置的显示名称。
  • 所有提供者都不包括模拟器上设置的显示名称。那是因为模拟器只接受你提供给它的有效载荷。它不会访问您的实际数据库/身份验证来检查该 uid 是否具有相应的显示名称。
  • 这个我明白,但我认为实际的 auth.token 将包含显示名称
  • 当您在真实应用程序中进行测试时,它确实包含它。只是在模拟器上默认不包含它。
  • @RosárioPereiraFernandes 这是一个超级答案。我认为您还应该在展示如何在模拟器中为自定义有效负载编写 JSON 的部分中提到......如果有人需要测试他们的 CustomClaims,例如。 "moderator":true"admin": true,即添加这些 KeyValue 对的地方(在 token{} 内)。因为在 firebase 文档中没有提到这个设置。将为开发人员节省大量时间。再次感谢。
猜你喜欢
  • 2021-10-11
  • 2016-06-08
  • 2019-07-10
  • 2019-03-06
  • 2012-12-16
  • 1970-01-01
  • 2017-05-07
  • 2021-01-22
  • 2019-02-08
相关资源
最近更新 更多