You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何配置Firebase规则阻止用户删除他人数据并允许新用户注册?

问题

我在游戏开发中使用Firebase,当前配置的Firebase规则如下:

{
  "rules": {
    ".read": true,
    ".write": "auth != null",
  "users": {
      ".indexOn": ["nickname", "attackPoints"],
      "$uid": {
        "nickname": {
          ".validate": "newData.val().matches(/^[a-zA-Z0-9_]+$/)" ,
          ".read": true,
          ".write": "$uid === auth.uid"
        },
        "gold": {
          ".read": "$uid === auth.uid",
          ".write": "$uid === auth.uid && newData.isNumber() && ((newData.val() >= 0 && newData.val() <= (data.val() + 1000)) || (data.exists() === false && newData.val() <= 1000))"
        },
        "experience": {
          ".read": "auth != null",
          ".write": "$uid === auth.uid && newData.isNumber() && ((newData.val() >= 0 && newData.val() <= (data.val() + 1000)) || (data.exists() === false && newData.val() <= 1000))"
        },
        "attackPoints": {
          ".read": "auth != null",
          ".write": "$uid === auth.uid && newData.isNumber() && ((newData.val() >= 0 && newData.val() <= (data.val() + 1000)) || (data.exists() === false && newData.val() <= 1000))"
        },
        "characterImageName": {
          ".read": "auth != null",
          ".write": "$uid === auth.uid"
        },
        "work": {
          ".read": "$uid === auth.uid",
          ".write": "$uid === auth.uid"
        },
        "inventory": {
          ".read": "auth != null",
          ".write": "$uid === auth.uid"
        },
                "attacks": {
          "$attackId": {
            ".validate": "newData.child('attacker').val() === auth.uid || newData.child('target').val() === auth.uid || newData.child('target').val() === $uid",
            ".read": "$uid === auth.uid || data.child('attacker').val() === auth.uid",
            ".write": "$uid === auth.uid || newData.child('attacker').val() === auth.uid || newData.child('target').val() === auth.uid"
          }
        }
      }
    }
  }
}

现在遇到两个问题:

  • 用户X可以删除其他用户(如userY)的gold等数据
  • 尝试移除根节点的".write": "auth != null",规则后,新用户注册时触发权限拒绝错误,注册代码如下:
val nicknameRef = database.child("users").orderByChild("nickname").equalTo(nick)
nicknameRef.addListenerForSingleValueEvent(object : ValueEventListener {
    override fun onDataChange(snapshot: DataSnapshot) {
        if (snapshot.exists()) {
            // Username is already taken
            showErrorDialog(getString(R.string.username_is_already_taken))
        } else {
            // Username is available, proceed with registration
            auth.createUserWithEmailAndPassword(email, password)
                .addOnCompleteListener(this@Register) { task ->
                    if (task.isSuccessful) {
                        val user = auth.currentUser
                        val userId = user?.uid

                        if (userId != null) {
                            val userData = HashMap<String, Any>()
                            userData["nickname"] = nick
                            userData["experience"] = 0
                            userData["gold"] = 200
                            userData["attackPoints"] = 35
                            userData["characterImageName"] = profile

                            database.child("users").child(userId).setValue(userData)
                                .addOnCompleteListener { dbTask ->
                                    if (dbTask.isSuccessful) {
                                        // Registration and data storage successful
                                        navigateToHome()
                                    } else {
                                        showErrorDialog(
                                            getString(
                                                R.string.error_while_saving_user_data_in_database,
                                                dbTask.exception?.message
                                            ))
                                    }
                                }
                        }
                    } else {
                        showErrorDialog(
                            getString(
                                R.string.registration_error,
                                task.exception?.message
                            ))
                    }
                }
        }
    }
})

请问如何调整Firebase规则,既阻止用户删除他人数据,又能让新用户正常完成注册?

解决方案

问题根源

  • 根节点的.write: auth != null是全局写权限,只要用户登录就能修改/删除任何路径的数据,包括其他用户的节点,这是导致用户能删除他人数据的核心原因。
  • 移除全局写权限后,注册时创建users/$uid节点没有对应的权限,所以触发拒绝错误。

调整后的规则

{
  "rules": {
    ".read": true,
    "users": {
      ".indexOn": ["nickname", "attackPoints"],
      "$uid": {
        // 允许用户创建自己的节点,或修改自己的节点,但禁止删除整个用户节点
        ".write": "$uid === auth.uid && newData.exists()",
        "nickname": {
          ".validate": "newData.val().matches(/^[a-zA-Z0-9_]+$/)",
          ".read": true,
          // 禁止删除nickname,要求新数据必须存在且符合格式
          ".write": "$uid === auth.uid && newData.exists()"
        },
        "gold": {
          ".read": "$uid === auth.uid",
          // 禁止删除gold,同时保留原有的数值校验规则
          ".write": "$uid === auth.uid && newData.exists() && newData.isNumber() && ((newData.val() >= 0 && newData.val() <= (data.val() + 1000)) || (data.exists() === false && newData.val() <= 1000))"
        },
        "experience": {
          ".read": "auth != null",
          // 禁止删除experience,保留数值校验
          ".write": "$uid === auth.uid && newData.exists() && newData.isNumber() && ((newData.val() >= 0 && newData.val() <= (data.val() + 1000)) || (data.exists() === false && newData.val() <= 1000))"
        },
        "attackPoints": {
          ".read": "auth != null",
          // 禁止删除attackPoints,保留数值校验
          ".write": "$uid === auth.uid && newData.exists() && newData.isNumber() && ((newData.val() >= 0 && newData.val() <= (data.val() + 1000)) || (data.exists() === false && newData.val() <= 1000))"
        },
        "characterImageName": {
          ".read": "auth != null",
          // 禁止删除characterImageName
          ".write": "$uid === auth.uid && newData.exists()"
        },
        "work": {
          ".read": "$uid === auth.uid",
          // 禁止删除work
          ".write": "$uid === auth.uid && newData.exists()"
        },
        "inventory": {
          ".read": "auth != null",
          // 禁止删除inventory
          ".write": "$uid === auth.uid && newData.exists()"
        },
        "attacks": {
          "$attackId": {
            ".validate": "newData.child('attacker').val() === auth.uid || newData.child('target').val() === auth.uid || newData.child('target').val() === $uid",
            ".read": "$uid === auth.uid || data.child('attacker').val() === auth.uid",
            // 允许创建/修改攻击记录,但禁止删除
            ".write": "newData.exists() && ($uid === auth.uid || newData.child('attacker').val() === auth.uid || newData.child('target').val() === auth.uid)"
          }
        }
      }
    }
  }
}

关键修改说明

  1. 移除根节点全局写权限:彻底避免任何登录用户随意修改其他用户数据的可能。
  2. 给users/$uid层级添加写规则:
    • $uid === auth.uid:确保只有用户自己能操作自己的节点
    • newData.exists():禁止删除整个用户节点(删除操作时newData不存在)
  3. 给所有子节点补充newData.exists():禁止用户删除自己的gold、nickname等子节点,如果业务需要允许删除特定子节点,可以单独移除该节点的newData.exists()限制。
  4. 注册流程适配:注册时调用setValue(userData)是创建自己的users/$uid节点,此时$uid等于当前用户的auth.uid,且节点原本不存在,符合$uid === auth.uid && newData.exists()的规则,所以能正常写入。

内容的提问来源于stack exchange,提问作者RGS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 03:17:36