问题
我已多次看到这个问题(也在Firebase实时数据库的上下文中),但我还没有看到令人信服的答案.问题陈述相当简单:
(经过身份验证的)用户如何选择尚未使用的用户名?
首先,原因是:用户进行身份验证后,他们拥有唯一的用户ID.然而,许多网络应用程序允许用户选择"显示名称"(用户希望如何在网站上显示),以保护用户的个人数据(如真实姓名).
用户集合
给定如下的数据结构,可以为每个用户存储用户名和其他数据:
/users (collection)
/{uid} (document)
- name: "<the username>"
- foo: "<other data>"
Run Code Online (Sandbox Code Playgroud)
但是,没有什么能阻止另一个用户(具有不同的用户{uid})将其存储name在他们的记录中.据我所知,没有"安全规则"允许我们检查name其他用户是否已经访问过.
注意:可以进行客户端检查,但作为恶意客户端的不安全可能会忽略检查.
反向映射
流行的解决方案是创建一个带有反向映射的集合:
/usernames (collection)
/{name} (document)
- uid: "<the auth {uid} field>"
Run Code Online (Sandbox Code Playgroud)
鉴于此反向映射,可以编写安全规则以强制尚未使用用户名:
match /users/{userId} {
allow read: if true;
allow create, update: if
request.auth.uid == userId &&
request.resource.data.name is string &&
request.resource.data.name.size() >= 3 &&
get(/PATH/usernames/$(request.resource.data.name)).data.uid == userId;
}
Run Code Online (Sandbox Code Playgroud)
并强制用户首先创建用户名文档:
match /usernames/{name} {
allow read: if true;
allow create: if
request.resource.data.size() …Run Code Online (Sandbox Code Playgroud) 我发现这个问题在这里相对经常被问到,但我仍然不知道如何管理独特属性的规则。我有以下文档数据模型:
users/{usereId}/Object
users/usernames/Object
Run Code Online (Sandbox Code Playgroud)
第一个对象包含有关用户的基本信息,例如:
{
email: "example@hotmail.edu"
photoURL: null
providerId: null
role: "admin"
username:"hello_world"
}
Run Code Online (Sandbox Code Playgroud)
同时 usernames 对象仅包含 作为username属性键和作为uid值,例如:
{
hello_world:"F3YAm8ynF1fXaurezxaQTg8RzMB3"
}
Run Code Online (Sandbox Code Playgroud)
我这样设置是因为我希望每个用户都有一个唯一的用户名。迭代第二个对象比迭代第一个对象消耗的时间更少。但回到我的问题。我需要它hello_world在写操作中是唯一的。但到目前为止我的规则还不起作用。我有:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth.uid != null
}
match /users/{userID} {
allow create: if !exists(/databases/$(database)/documents/users/$(request.resource.data.username)) <== does not apply
}
}
}
Run Code Online (Sandbox Code Playgroud)
第二个匹配是,什么应该应用唯一属性规则。有谁知道如何正确设置规则?
我的数据库(firestore)中有以下字符集合结构
/characters/{uid}
- username: string
- clan: string
- mana: number
- health: number
etc...
Run Code Online (Sandbox Code Playgroud)
我正在尝试/characters/{uid}通过以下逻辑找出安全规则
service cloud.firestore {
match /databases/{database}/documents {
// Characters
match /characters/{characterID} {
allow create: if isValidUsername();
}
}
}
Run Code Online (Sandbox Code Playgroud)
这里的函数isValidUsername检查各种内容,如长度、特殊字符等......但我无法弄清楚的一件事是如何检查函数内部
确保它request.resource.data.username是唯一的,即不存在于任何其他/characters收藏文档中。