Firebase写入父节点,但阻止直接写入子节点

Firebase写入父节点,但阻止直接写入子节点,firebase,firebase-security,Firebase,Firebase Security,我有一个用例,在这个用例中,我需要一个用户向Firebase中的某个位置提供一组数据,但不能一次更改该位置的单个子节点 例如,假设我有一个用户能够写入另一个系统正在监视的树,请求,以便它能够处理请求。此外,我们没有使用.push()生成Firebase pushID来唯一标识请求,而是使用一个单独的位置来写入请求。结构可以如下所示: requests: { UserID1: { requestParam1: "Some parameter", requestParam2: "

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

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

requests: {
  UserID1: {
    requestParam1: "Some parameter",
    requestParam2: "Another parameter"
  }
}
需要明确的是,处理请求的系统将侦听
请求/UserID1
,以便收到结构更改的通知并处理请求

还可以说,
requestParam1
requestParam2
都是必需的。每次写入
UserID1
节点时都需要这些参数的原因是为了防止用户只写入
requestParam1
,然后处理请求的系统不会收到实质上接收新的
requestParam1
和旧的
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
时,尝试是成功的,这不是期望的行为

我在两个
请求参数中都包含了
“.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
    }
  }
}
//before:
var data = "Some data"

/after:
var data = {
  ".value": "Some data",
  ".priority": Firebase.ServerValue.TIMESTAMP
}
我不确定是否要添加
newData.parent().exists()
检查,所以我把它放在那里进行了适当的测量,但我认为
newData().parent().hasChildren([…])
规则会使这一切都起作用,但我错了。仍允许向单个子级写入

想法

编辑1:


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

正如@AnidMonsur所指出的,
newData
是现有数据加上正在写入的新数据的“合并”(),因此,不仅仅是新的数据,这无疑使这个问题更难回答

实现这一点的一个潜在方法是确保将写入每个位置的新数据与该位置已有的数据(如果存在)不同。但是,如果用户打算将相同的数据写入字段,那么这不是一个可行的解决方案

然而,我认为我有一个可能有效的替代方案。对于每段数据,即
requestParam1
requestParam2
,规则应强制执行规则的优先级等同于并确保数据的优先级匹配。这将强制发出请求的客户机在每个数据段的每个请求中包含优先级。这将导致以下规则:

"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
    }
  }
}
我不确定是否有办法颠覆这一策略。。。我想两个用户可以同时向这两个位置写入数据,但我不知道如何避免(另外,这似乎不太可能)

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

"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
    }
  }
}
//before:
var data = "Some data"

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

我认为这是不可能的
newData
包含合并结果,因此您不能仅对更新的数据强制执行规则。@AnidMonsur,您认为“
newData
包含合并结果”是什么意思?我认为
newData
包含将要写入该位置的数据,因此可以在实际写入该位置之前通过
规则进行检查。从文档中可以看出:@AnidMonsur,感谢您指出-
newData
的名称现在比我原来认为的更混乱。