我正在使用FirebaseSimpleLogin
创建用户并处理身份验证。
当我尝试通过$createUser()
方法创建一个简单登录的新用户时,如果电子邮件地址已经被使用,firebase将不会创建该用户。但是,我还使用$set()
将创建的用户保存到我的firebase,并使用user.uid
作为密钥。当尝试写入数据库时,即使用户名不是唯一的,firebase也会保存记录,因为简单的登录只需要电子邮件和密码。那么,当用户名没有被用作user对象的键时,如何验证它是唯一的呢?
我正在创建这样的新用户:
$scope.createUser = function() {
$scope.auth.$createUser('trinker@gmail.com', 'password').then(function(user, err) {
if (!err) {
ref.child('users/' + user.uid).set({
email: user.email,
username: user.username
});
console.log("success!");
}else{
console.log(err.message);
}
});
}
我的用户对象是这样的
{
"users" : {
"simplelogin:28" : {
"email" : "trinker@gmail.com",
"username" : "jtrinker"
},
"simplelogin:30" : {
"email" : "test@gmail.com",
"username" : "jtrinker"
}
}
}
}
我需要使用uid作为每个用户的键,但是我仍然需要用户名是唯一的。
如果一个对象中的属性对另一个对象中的属性不是唯一的,我怎么能阻止firebase保存记录?
首先,如果用户已经有一个username
,它是唯一的,这不会消失,我建议你放弃使用简单的登录uid
。正如您在这里已经发现的那样,这将只会产生在两者之间来回切换的问题。研究使用firebase-passport-login等工具创建自己的令牌,然后通过username
存储记录。
但既然这不是你的问题,让我们在这里解决这个问题,因为你可能想继续进入双重身份的荆棘,我已经多次走过了。
为了使用户名唯一,存储一个用户名索引。
/users/$userid/username/$username
/usernames/$username/$userid
要确保它们是唯一的,请在usernames/path中的用户id上添加如下安全规则,以确保每个用户名只能分配一个用户,并且该值是用户的id:
".write": "newData.val() === auth.uid && !data.exists()"
现在通过向users/record中的用户名添加以下内容来强制它们匹配:
"users": {
"$userid": {
"username": {
".validate": "root.child('usernames/'+newData.val()).val() === $userid"
}
}
}
这将确保id是唯一的。小心使用读权限。你可能想要完全避免这些,因为你不希望任何人看到私人电子邮件或用户名。像我演示的那样支持保存这些文件将是理想的。
这里的想法是,您尝试分配用户名和电子邮件,如果他们失败,那么他们已经存在,属于另一个用户。否则,将它们插入到用户记录中,现在就有了按uid和电子邮件索引的用户。
为了遵守SO协议,下面是该要点的代码,最好通过链接阅读:
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": {
// not readable, cannot get a list of emails!
// can only write if this email is not already in the db
".write": "!data.exists()",
// can only write my own uid into this index
".validate": "newData.val() === auth.uid"
}
},
"username_lookup": {
"$username": {
// not readable, cannot get a list of usernames!
// can only write if this username is not already in the db
".write": "!data.exists()",
// can only write my own uid into this index
".validate": "newData.val() === auth.uid"
}
},
}
}
直接使用安全规则来检查它是否存在不是更容易吗?我的设置如下:
"usernames": {
"$usernameid": {
".read": "auth != null",
".write": "auth != null && (!data.exists() || !newData.exists())"
}
}
允许在用户名不存在的情况下写入。