【问题标题】:Firebase write to parent node but prevent writing direct to child nodesFirebase 写入父节点,但阻止直接写入子节点
【发布时间】:2015-10-08 18:45:18
【问题描述】:

我有一个用例,我需要用户向 Firebase 中的某个位置提供一组数据,但不能一次更改该位置的各个子节点。

举个例子,假设我有一个用户能够写入树,requests,另一个系统正在监视它以便它可以处理请求。此外,我们没有使用 .push() 生成 Firebase pushID 来唯一标识请求,而是只有一个写入请求的单一位置。结构可能如下所示:

requests: {
  UserID1: {
    requestParam1: "Some parameter",
    requestParam2: "Another parameter"
  }
}

需要明确的是,处理请求的系统会监听requests/UserID1,以便在结构发生任何变化时收到通知并处理请求。

假设requestParam1requestParam2 始终是必需的。每次写入UserID1 节点都需要这些参数的原因是为了防止用户 写入requestParam1,然后处理请求的系统不会收到实质上的请求收到 new requestParam1old requestParam2

确保在写入UserID1 时包含两个参数很简单,但我不知道如何直接停止对子节点的写入。

到目前为止,这是我的规则:

"requests": {
  "$userID": {
    ".write": "auth !== null && newData.exists()",
    ".validate": "newData.hasChildren(['requestParam1', 'requestParam2'])"
    "requestParam1": {
      ".validate": "newData.isString()"
    },
    "requestParam2": {
      ".validate": "newData.isString()"
    }
    "$other": {
      ".validate": false
    }
  }
}

如果我尝试在没有任何请求参数的情况下写入UserID1,它会拒绝写入——这是正确的。但是,当我直接写信给UserID1/requestParam1 时,尝试成功,这不是预期的行为。

我在两个requestParam 中都包含了".write": false 规则,但仍然允许写入。我相信这是因为父节点中的写入规则认为写入是允许的,因此会级联到子节点。根据文档,我认为没有办法解决这个问题。但是,我想我会变得聪明,让每个子节点检查newData.parent() 的子内容,如下所示:

"requests": {
  "$userID": {
    ".write": "auth !== null && newData.exists()",
    ".validate": "newData.hasChildren(['requestParam1', 'requestParam2'])"
    "requestParam1": {
      ".validate": "
        newData.parent().exists() &&
        newData.parent().hasChildren(['requestParam1', 'requestParam2']) &&
        newData.isString()
      "
    },
    "requestParam2": {
      ".validate": "
        newData.parent().exists() &&
        newData.parent().hasChildren(['requestParam1', 'requestParam2']) &&
        newData.isString()
      "
    }
    "$other": {
      ".validate": false
    }
  }
}

我不确定是否要添加newData.parent().exists() 检查,所以我把它扔在那里以防万一,但我认为newData().parent().hasChildren([...]) 规则会使这一切正常工作,但我错了。仍然允许写给单个孩子。

想法?

编辑 1:

我还尝试将之前在.validate 部分中的newData.hasChildren([...]) 规则移动到$userID 规则中的.write 部分,但没有成功。

【问题讨论】:

  • 我认为这是不可能的。 newData 包含合并的结果,因此您不能仅对更新的数据强制执行规则。
  • @AnidMonsur,“newData 包含合并结果”是什么意思?我认为newData 包含要写入该位置的about 数据,以便在实际写入该位置之前可以通过.validate 规则对其进行检查。
  • @AnidMonsur,感谢您指出这一点 - newData 这个名字现在比我原先想象的更令人困惑。

标签: firebase firebase-security


【解决方案1】:

正如@AnidMonsur 所指出的,newData“是现有数据加上正在写入的新数据的‘合并’”(from the docs),所以它并不是真正只是新数据,这无疑使问题更难回答。

实现此目的的一种可能方法是确保将写入每个位置的 newData 不同于该位置已经存在的数据(如果存在)。但是,如果用户打算将相同的数据写入字段,这不是一个可行的解决方案。

但是,我认为我有一个可行的替代方案。对于每条数据,即requestParam1requestParam2,规则应强制规则的优先级 等效于now,并确保数据的优先级匹配。这将强制发出请求的客户端在每条数据的每个请求中包含优先级。这会产生以下规则:

"requests": {
  "$userID": {
    ".write": "auth !== null && newData.exists()",
    ".validate": "newData.hasChildren(['requestParam1', 'requestParam2'])"
    "requestParam1": {
      ".validate": "
        newData.isString() &&
        newData.getPriority() !== null &&
        newData.getPriority() === now &&
        newData.parent().child('requestParam2').getPriority() === newData.getPriority()
      "
    },
    "requestParam2": {
      ".validate": "
        newData.isString() &&
        newData.getPriority() !== null &&
        newData.getPriority() === now &&
        newData.parent().child('requestParam1').getPriority() === newData.getPriority()
      "
    }
    "$other": {
      ".validate": false
    }
  }
}

我不确定是否有办法颠覆这个策略...我想两个用户可以可能同时写入两个位置,但我'我不确定如何避免这种情况(另外,这似乎不太可能)。

另外,作为旁注,如果有人想知道如何在您的数据中包含一个优先级(如果它只是一个字符串/数字/布尔类型),您可以按如下方式在写入中构造数据:

//before:
var data = "Some data"

/after:
var data = {
  ".value": "Some data",
  ".priority": Firebase.ServerValue.TIMESTAMP
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 2021-02-25
    • 1970-01-01
    • 2010-12-03
    • 1970-01-01
    • 1970-01-01
    • 2021-12-05
    相关资源
    最近更新 更多