Parseは年末にシャットダウンするため、Firebaseの使用を開始することにしました。メール、ユーザー名、パスワードの3つのフィールドで登録プロセスを実装する必要があります(Email&usernameはアプリで一意である必要があります)。
FirebaseはParseのようなユーザー名を管理する簡単な方法を提供していないため、メール/パスワード登録のみを使用し、usernameなどの追加データを保存することにしました。ユーザーデータ構造は次のとおりです。
app : {
users: {
"some-user-uid": {
email: "[email protected]"
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: "[email protected]"
username: "myname"
}
},
usernames: {
"myname": "some-user-uid"
}
}
したがって、usernames
ノードはユーザー名をuidにマップします。基本的には、「ユーザー名「myname」は「some-user-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"
}
}
}
これは、ユーザー名がまだ誰にも要求されていないことを検証しますOR現在のユーザーに要求されています。
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
}
}
});