ユーザーの作成と認証の処理にFirebaseSimpleLogin
を使用しています。
$createUser()
メソッドを使用して単純なログインで新しいユーザーを作成しようとすると、メールアドレスがすでに使用されている場合、firebaseはユーザーを作成しません。ただし、作成したユーザーを$set()
を使用してFirebaseに保存し、user.uid
をキーとして使用しています。データベースに書き込もうとすると、Firebaseはユーザー名が一意でない場合でもレコードを保存します。これは、単純なログインに必要なのはEメールとパスワードのみであるためです。それでは、ユーザー名がユーザーオブジェクトのキーとして使用されていない場合、ユーザー名が一意であることをどのように検証できますか?
私はこのような新しいユーザーを作成しています:
$scope.createUser = function() {
$scope.auth.$createUser('[email protected]', '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" : "[email protected]",
"username" : "jtrinker"
},
"simplelogin:30" : {
"email" : "[email protected]",
"username" : "jtrinker"
}
}
}
}
各ユーザーのキーとしてuidを使用する必要がありますが、ユーザー名は一意である必要があります。
あるオブジェクト内のプロパティが別のオブジェクト内のプロパティに一意でない場合、firebaseがレコードを保存しないようにするにはどうすればよいですか?
まず、ユーザーがすでにusername
を持っている場合、それは一意であり、これがなくなるわけではないので、単純なログインuid
sの使用を断念することをお勧めします。ここですでに発見したように、これは2つの間を行き来しようとする問題以外に何も作成しません。 firebase-passport-login のようなツールで 独自のトークンを作成する を調査し、username
でレコードを保存します。
しかし、それはあなたの質問ではなかったので、私たちがここにいる間、それを解決しましょう。あなたが先に進んで、私が何度も通過した二重のアイデンティティの厄介なブライヤーを入力したい場合があるからです。
ユーザー名を一意にするには、ユーザー名のインデックスを保存します。
/users/$userid/username/$username
/usernames/$username/$userid
それらが一意であることを確認するには、usernames /パスのユーザーIDに次のようにセキュリティルールを追加します。これにより、ユーザー名ごとに1人のユーザーのみが割り当てられ、値はユーザーのIDになります。
".write": "newData.val() === auth.uid && !data.exists()"
次に、users /レコードのユーザー名に以下を追加して、それらが一致することを強制します。
"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": {
// 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())"
}
}
これにより、ユーザー名が存在しない場合でも書き込みが可能になります。これはFirebaseのドキュメントから直接入手したと思います。