问题
我已多次看到这个问题(也在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) 在我的代码使用模板图像类Image<T>与组合std::shared_ptr.这些图像指针应该被传递给各种图像处理功能,其中一些功能与图像类型无关.考虑以下定义Image<T>,以及两个处理函数function1()和function2().
#include <memory>
template <typename T>
struct Image
{
typedef std::shared_ptr<Image<T>> Ptr;
};
template <typename T>
void function1 (typename Image<T>::Ptr image) {}
template <typename T>
void function2 (std::shared_ptr<Image<T>> image) {}
Run Code Online (Sandbox Code Playgroud)
虽然function1()并且function2()有效地具有相同的签名,但是function1()更容易阅读并隐藏指针如何实现的细节.但是,我在function1()没有明确指定模板类型的情况下无法调用.请考虑以下代码:
int main (void)
{
Image<int>::Ptr image = std::make_shared<Image<int>>();
function1(image); // Does NOT compile
function1<int>(image); // Does compile
function2(image); // Does compile
return 0;
}
Run Code Online (Sandbox Code Playgroud)
第一次调用导致编译错误:
example.cc: In function 'int main()':
example.cc:18:19: …Run Code Online (Sandbox Code Playgroud)