首先,如果用户已经有一个{username},它是唯一的,并且不会消失,我建议您放弃使用简单的登录{uid},这样只会在两者之间来回切换时创建问题,正如您在这里已经发现的那样。可以考虑使用
firebase-passport-login这样的工具,通过
creating your own tokens来存储记录 {username}。
但既然这不是您的问题,我们就在这里解决一下,因为您可能想进入我已经通过多次的双重身份的荆棘丛中。
要使{username}唯一,请存储用户名索引。
/users/$userid/username/$username
/usernames/$username/$userid
为确保它们是唯一的,请在用户名/路径中的用户ID上添加以下安全规则,以确保每个用户名只能分配一个用户,并且该值为用户的ID:
".write": "newData.val() === auth.uid && !data.exists()"
现在我们需要确保它们匹配,可以通过在用户记录(users/)中的用户名(username)后面添加以下内容来实现:
"users": {
"$userid": {
"username": {
".validate": "root.child('usernames/'+newData.val()).val() === $userid"
}
}
}
这将确保ID是唯一的。小心阅读权限。你可能想完全避免它们,因为你不希望任何人查找私人电子邮件或用户名。
像我在支持中演示的那样,保存这些内容是理想的。
这里的思路是,你尝试分配用户名和电子邮件,如果失败,则它们已经存在并属于另一个用户。否则,你将它们插入到用户记录中,现在已经通过uid和电子邮件索引了用户。
为了遵守SO协议,这是来自那个gist的代码,最好通过链接阅读:
var fb = new Firebase(URL);
function escapeEmail(email) {
return email.replace('.', ',');
}
function claimEmail(userId, email, next) {
fb.child('email_lookup').child(escapeEmail(email)).set(userId, function(err) {
if( err ) { throw new Error('email already taken'); }
next();
});
}
function claimUsername(userId, username, next) {
fb.child('username_lookup').child(username).set(userId, function(err) {
if( err ) { throw new Error('username already taken'); }
next();
});
}
function createUser(userId, data) {
claimEmail(userId, data.email, claimUsername.bind(null, userId, data.username, function() {
fb.child('users').child(userId).set(data);
);
}
还有规则:
{
"rules": {
"users": {
"$user": {
"username": {
".validate": "root.child('username_lookup/'+newData.val()).val() === auth.uid"
},
"email": {
".validate": "root.child('email_lookup').child(newData.val().replace('.', ',')).val() === auth.uid"
}
}
},
"email_lookup": {
"$email": {
".write": "!data.exists()",
".validate": "newData.val() === auth.uid"
}
},
"username_lookup": {
"$username": {
".write": "!data.exists()",
".validate": "newData.val() === auth.uid"
}
},
}
}