Firebase android:使用户名唯一
Parse将在年底关闭,因此我决定开始使用Firebase。我需要使用3个字段实施注册过程:电子邮件、用户名、密码(电子邮件和用户名对于我的应用程序必须是唯一的) 因为Firebase没有提供一种简单的方法来管理用户名解析,所以我决定只使用电子邮件/密码注册,并保存一些额外的数据,比如用户名。以下是我的用户数据结构:Firebase android:使用户名唯一,android,firebase,firebase-security,firebase-authentication,Android,Firebase,Firebase Security,Firebase Authentication,Parse将在年底关闭,因此我决定开始使用Firebase。我需要使用3个字段实施注册过程:电子邮件、用户名、密码(电子邮件和用户名对于我的应用程序必须是唯一的) 因为Firebase没有提供一种简单的方法来管理用户名解析,所以我决定只使用电子邮件/密码注册,并保存一些额外的数据,比如用户名。以下是我的用户数据结构: app : { users: { "some-user-uid": { email: "test@test.com"
app : {
users: {
"some-user-uid": {
email: "test@test.com"
username: "myname"
}
}
}
但是,我想做的是使用户名唯一,并在创建帐户之前检查它。
以下是我的规则:
{
"rules": {
".read": true,
".write": true,
"users": {
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": "auth !== null && auth.provider === 'password'",
"username": {".validate": "!root.child('users').child(newData.child('username').val()).exists()"}
}
}
}
}
非常感谢您的帮助部分答案是存储用户名索引,您可以在安全规则中进行检查:
app : {
users: {
"some-user-uid": {
email: "test@test.com"
username: "myname"
}
},
usernames: {
"myname": "some-user-uid"
}
}
因此,usernames
节点将用户名映射到uid。它的基本意思是“用户名‘myname’属于‘某个用户uid’”
使用此数据结构,您的安全规则可以检查给定用户名是否已有条目:
"users": {
"$uid": {
".write": "auth !== null && auth.uid === $uid",
".read": "auth !== null && auth.provider === 'password'",
"username": {
".validate": "
!root.child('usernames').child(newData.val()).exists() ||
root.child('usernames').child(newData.val()).val() == $uid"
}
}
}
这将验证用户名是否尚未被任何人声明,或者是否已被当前用户声明。我还不太了解firebase安全性,但我可能已经使用Java解决了这个问题。我已经把它贴在下面了 我的数据结构是
myapp
{
users: {
<unique generated-id>
{ username: "example.username" }
}
}
public boolean isUsernameExists(final String enteredUsername) {
final Boolean[] isExist = {false};
FBref.child("users").addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot userSnapshot : dataSnapshot.getChildren()) {
String existingUsername = (String) userSnapshot.child("userName").getValue();
if (existingUsername.equals(enteredUsername)) {
isExist[0] = true;
}
}
}
@Override
public void onCancelled(FirebaseError firebaseError) {
//some error thrown here
}
});
return isExist[0];
}
myapp
{
用户:{
{username:“example.username”}
}
}
公共布尔值IsUserName存在(最终字符串enteredUsername){
最终布尔值[]isExist={false};
FBref.child(“用户”).addValueEventListener(新的ValueEventListener(){
@凌驾
公共void onDataChange(DataSnapshot DataSnapshot){
对于(DataSnapshot userSnapshot:DataSnapshot.getChildren()){
字符串existingUsername=(字符串)userSnapshot.child(“用户名”).getValue();
if(existingUsername.equals(enteredUsername)){
isExist[0]=真;
}
}
}
@凌驾
取消后的公共无效(FirebaseError FirebaseError){
//这里抛出了一些错误
}
});
返回isExist[0];
}
按照Frank的建议保存用户名,但在保存用户名时,请使用Firebase中的runTransaction函数确保未使用用户名。Firebase保证此功能为原子操作,因此您可以放心,不会发生碰撞
firebaseRef.child("usernames").child(username).runTransaction(new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData mutableData) {
if (mutableData.getValue() == null) {
mutableData.setValue(authData.getUid());
return Transaction.success(mutableData);
}
return Transaction.abort();
}
@Override
public void onComplete(FirebaseError firebaseError, boolean commited, DataSnapshot dataSnapshot) {
if (commited) {
// username saved
} else {
// username exists
}
}
});
那么,你想在Android客户端上检查Firebase规则吗?是的,我想首先检查用户名是否被占用如果Firebase告诉我否,然后创建一个帐户,否则只需让用户从我关于数据结构和安全规则的回答中选择另一个用户名,以下是一些以前讨论过的问题:,很好的回答,与Hi Frank重复,我认为还需要注意的是,您可能应该将所有对
用户名的检查转换为小写,并存储小写,这样您就不能有大小写不同的相同用户名。存储在users/some user uid/username
字段中的值可以区分大小写,也可以是可读的版本,这应该允许用户更友好地选择用户名和遵守大小写。@Frank van Puffelen您能确认Viv在回答中关于使用横切而不是普通集合查询的说法吗?还有,你以前写的任何正则表达式都可以用来验证用户名中允许的字符?谢谢你的回答!它真的帮助了我。但我想还是有一个问题。。在您当前的实现中,同一个用户可以声明他想要的任意多的用户名(如果没有使用)。所以他基本上可以创建username1直到usernameN。我们如何才能实现在他声明新用户名之前删除旧用户名?使用一个反向数据结构,将uid
映射到username
,然后验证uid
->username
===用户名
->uid
。您在用户名列表中设置它,但不在uid中设置它。我们应该在complete上添加一行吗?