在 Firebase 实时数据库规则中验证匿名用户的显示名称

Posted

技术标签:

【中文标题】在 Firebase 实时数据库规则中验证匿名用户的显示名称【英文标题】:Verifying an anonymous user's display name in Firebase realtime database rules 【发布时间】: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", 【参考方案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 文档中没有提到这个设置。将为开发人员节省大量时间。再次感谢。

以上是关于在 Firebase 实时数据库规则中验证匿名用户的显示名称的主要内容,如果未能解决你的问题,请参考以下文章

用于 Firebase 实时数据库/Firebase 身份验证的 Android 唯一密钥

Firebase 实时数据库规则拒绝权限

Firebase 实时电话数据库安全规则

如何在没有身份验证的情况下添加 Firebase 数据库规则?

多个用户的 Firebase 实时数据库身份验证

如果我在 firebase 身份验证中有很多冗余匿名用户,可以吗? [关闭]