我想确保可以(从客户端)创建新用户,但只有经过身份验证的用户才能读取或写入现有对象。
我有一个简单的规则集:
{
"rules": {
"users": {
"$uid": {
".read": "auth != null && auth.uid === $uid",
".write": "!data.exists() || auth.uid === $uid"
}
}
}
}
我正在调用createUser
,然后在回调中尝试向我自己的users
对象添加一个条目:
const usersRef = ref.child('users');
const userEntry = {
[userData.uid]: {
created: new Date().getTime()
}
};
usersRef.set(userEntry)
我本以为,即使用户还没有登录,他们也应该有写权限,因为!data.exists()
。然而,我得到了一个PERMISSION_DENIED
错误。
如果我在users
级别上设置".write": true
,那么它将级联(并覆盖?)我的内部规则,不是吗?
编辑:
即使使用也会失败
"users": {
"$uid": {
".read": true,
".write": true
}
}
谢谢。
我想我最初误解了这个问题。在当前回调中,由于集合的工作方式,您正试图覆盖整个用户级别。
你真的只想设置不存在的东西:
const userRef = ref.child('users').child(userData.uid);
const userEntry = {
created: new Date().getTime()
};
userRef.set(userEntry);
那么,我认为你现有的规则是可行的。
我认为这是一个令人困惑的问题,因为创建用户和写入数据库是完全不同的事情。所以我将在我的应用程序中展示我是如何做到这一点的。
- 第一步是创建用户
- 接下来让用户登录,因为创建不会自动让用户登录(我在createuser的回调函数中这样做)
- 最后一步是将用户数据写入firebase
我使用以下规则来确保每个用户只能在firebase(文档)中写入自己的节点:
{
"rules": {
"users": {
"$user_id": {
".write": "$user_id === auth.uid"
}
}
}
}
需要记住的一点是,set()将替换该路径上的任何现有数据。因此,请确保使用用户的uid,而不是users节点。
最后,我想指出你在问题中发布的规则中的一个巨大缺陷:
".write": "!data.exists() || auth.uid === $uid"
该规则规定,如果还没有任何数据,或者您有正确的uid,则可以进行写入。该语句的第一部分是问题所在,因为ANYONE可以在没有任何数据的情况下写入此位置。也因为$uid是一个动态路径,所以你可以在那里添加任何东西,比如:
"users": {
"WoWIjustMadeThisUp": {
"nice": "Some huge value making you go over your limit"
}
}
如果你希望用户只写一个初始值,之后就无法编辑它,只需使用验证规则来检查该位置是否已经有数据。