唯一用户名的Firebase数据库规则

时间:2016-08-19 20:05:43

标签: firebase firebase-realtime-database firebase-security

我正在尝试创建一个使用Firebase数据库来存储用户信息的网站。我想使用唯一的用户名。我有两个索引,一个用于用户,另一个用于用户名。

我的数据库结构如下:

users {
  $uid {
    username: "username1",
    gender: "xyz"
    email: "xyz"
  }
},
usernames {
    "username1": $uid"
}

用户使用$ uid声明用户名。

这些是我的规则:

{
  "rules": {
    "users": {
      "$uid": {
        ".write": "auth !== null && auth.uid === $uid",
        ".read": "auth !== null && auth.uid === $uid",
        "username": {
          ".validate": "
            !root.child('usernames').child(newData.val()).exists() ||
            root.child('usernames').child(newData.val()).val() == $uid"
        }
      }
    },
    "usernames" : {
      ".write": "!data.exists() && auth!= null",
      ".validate": "newData.val() == auth.uid"  <---- I can't get this too work
    }
  }
}

在$ uid下设置用户名时,它会检查用户名索引,因此用户名只能使用未使用的用户名或者拥有自己的$ uid的用户名。

我只想要其中值是经过身份验证的用户uid且密钥是用户名的数据。我无法让这个工作。我怀疑我正在使用newData()。val()错误。我的验证声明失败了。

我想避免使用自定义令牌,但我愿意接受任何建议。提前谢谢。

很抱歉,如果这个解释过于简单,这是我在StackOverflow上的第二篇文章。

编辑#2 我从我能说的内容中做了一些研究,并且我在docs中找到了关于在.val()之前需要使用.child()的所有内容,但我需要.child来获取变量而不是set username。

2 个答案:

答案 0 :(得分:0)

很抱歉,如果我迟到了,但我遇到了类似的问题,我将我的用户名规则更改为以下功能:

"usernames" : {
  "$username": {
  ".write": "!data.exists() && auth!= null && newData.val() == auth.uid"
  }
 },
}

答案 1 :(得分:0)

一旦您想允许人们更改他们的用户名,接受的答案就会引起问题。

通过稍微改变您的数据库结构,您可以轻松地管理 firebase 中的用户名。您还可以允许用户更改其用户名。

数据库:

usernames: {
  username1: {
    owner: "userId1"
  },
  username2: {
    owner: "userId2"
  },
  ...
}

以下规则将:

  • 阻止任何用户更改/删除其他用户的用户名
  • 让新用户创建用户名
  • 让用户通过删除旧用户名并创建新用户名来更改用户名

(为了可读性而拆分换行符)

    "usernames": {
      "$username": {
        ".read": "true",
        ".write": "auth != null &&
          (
            \\ Allow user to delete only their own username
            (data.exists() && data.child('owner').val() === auth.uid && !newData.child('owner').exists())
            || 
            \\ Allow user to create a new username if the username is not taken
            (!data.exists() && newData.child('owner').val() === auth.uid)
          )"
      }
  }

此更新将创建一个用户:

  const toAdd = {}
  toAdd[`usernames/${username}`] = { owner: userId };
  firebase.database().ref().set(toAdd)

此更新将更改用户名:

const update = {}
update[`usernames/${previousUsername.toLowerCase()}`] = null;
update[`usernames/${newUsername.toLowerCase()}`] = { owner: userId };
firebase.database().ref().update(update)

在您的代码中,您还应该在发送更新之前查询数据库以检查用户名是否存在。

为什么我避免使用 username: userId 方法:

你说

<块引用>

编辑#2 我做了一些我能说的研究,所有我能在文档中找到的关于需要在 .val() 之前使用 .child() 但我需要 .child 来获取一个变量而不是一个集合用户名。

我相信这是正确的。对于您的用户名设置:

usernames {
    "username1": userId1,
    "username2": userId2,
    ...
}

This answer 描述了在请求中发送关键信息的方法:

ref.update({
_username: "username3",
username3: "userId3",
})

然后您可以使用类似的规则检查用户名是否在数据库中

data.child(newData.child('_username').val()).exists()

但是,在您的用户名设置中,您将使用此更新覆盖其他用户名。为避免这种情况,您需要在用户名 usernames/username3 = userId3 的路径中设置新数据。但是你不能像这样设置它,因为你会回到没有在规则中引用的键的问题。

您需要创建一个无意义的结构,例如:

usernames: {
  username1: {
    _username: "username1",
    userId: "userId1"
  }  
}

所以我选择了更简单但不幸的是我在开始时描述的用户名数据库设置稍微不那么漂亮。