Firebase Realtime Database仅创建安全规则配置不生效问题
核心错误原因
规则不生效源于对Firebase实时数据库规则机制的三个认知偏差:
.write/.read规则遵循自上而下级联生效逻辑:只要任意上层节点的.write判断为true,下层节点的.write规则会被直接跳过,权限无法被下层规则收回。.validate规则仅在.write权限校验通过后才会执行,之前把「仅允许新建不存在的卡组」的权限逻辑写在.validate中,根本无法拦截已授权的修改/删除操作。- 之前在
decks根节点配置的.write: "data.val() == null && newData.val() != null"规则,仅在整个decks根节点完全不存在时才会生效,只要decks下已经有任意一个卡组,该规则就会永久返回false,自然无法新建后续卡组。
正确规则配置
权限规则必须下沉到$deckId层级,不要配置在decks根节点,完整可直接使用的规则如下:
{ "rules": { "decks": { "$deckId": { // 核心权限控制:仅当前卡组节点不存在时允许写入,写入后永久禁止修改/删除 ".write": "!data.exists() && newData.exists()", // 校验卡组ID格式:必须为5位纯数字,且写入内容包含子节点 ".validate": "$deckId.matches(/^[0-9]{5}$/) && newData.hasChildren()", "$cardNumber": { // 校验卡牌编号格式:默认支持card001到card030大小写兼容写法 ".validate": "$cardNumber.matches(/^card0(0[1-9]|[12][0-9]|30)$/i)", "SetCode": { ".validate": "newData.isString() && newData.val().matches(/^[A-Z][a-z]{4}$/)" }, "SetID": { ".validate": "newData.isString() && newData.val().matches(/^[0-9]{3}$/)" }, // 拦截所有非预定义的非法字段 "$other": { ".validate": false } } } } } }
规则逻辑说明
- 核心权限逻辑放在
$deckId层级:针对每一个独立的卡组ID判断状态,只有当该ID对应的节点原本不存在、且操作不是删除操作时才放开写入权限,卡组创建完成后所有修改、删除请求都会直接被拒绝。 - 移除了之前写在
$deckId.validate中的存在性判断逻辑,该部分属于权限控制范畴,必须放在.write中执行。 - 优化了冗余正则:5位数字的正则
/^[0-9]{5}$/本身已经限制了长度,不需要额外判断length属性;卡牌编号的正则去掉了无意义的单字符字符组写法,默认支持大小写兼容,如果需要严格匹配首字母大写的Card0xx编号格式,把正则的i修饰符去掉,改为/^Card0(0[1-9]|[12][0-9]|30)$/即可。 - 新增非法字段拦截:避免卡牌节点下写入SetCode、SetID之外的脏数据。
- 写入注意事项:新建卡组必须一次性提交符合所有校验规则的完整数据,任意字段校验不通过时整个写入操作会整体回滚,不会产生半写入的脏数据。
内容的提问来源于stack exchange,提问作者Etherealscorpions
相关产品推荐
相关产品推荐

