web-dev-qa-db-fra.com

Firebase Android: rendre le nom d'utilisateur unique

Parse fermera ses portes à la fin de l'année, j'ai donc décidé de commencer à utiliser Firebase. J'ai besoin de mettre en œuvre un processus d'enregistrement avec 3 champs: email, nom d'utilisateur, mot de passe (Email & nom d'utilisateur doit être unique pour mon application).

Étant donné que Firebase ne fournit pas un moyen facile de gérer le nom d'utilisateur comme Parse, j'ai décidé d'utiliser uniquement l'enregistrement par e-mail/mot de passe et enregistrer des données supplémentaires comme le nom d'utilisateur. Voici la structure de données de mes utilisateurs:

app : {
    users: {
       "some-user-uid": {
            email: "[email protected]"
            username: "myname"
       }
    }
}

Mais ce que je veux faire, c'est rendre le nom d'utilisateur unique et le vérifier avant de créer un compte. Ce sont mes règles:

{
    "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()"}
            }
        }
   }
}

Merci beaucoup pour votre aide

31
FloGz

Une partie de la réponse consiste à stocker un index des noms d'utilisateurs, que vous vérifiez dans vos règles de sécurité:

app : {
    users: {
       "some-user-uid": {
            email: "[email protected]"
            username: "myname"
       }
    },
    usernames: {
        "myname": "some-user-uid"
    }
}

Ainsi, le nœud usernames mappe un nom d'utilisateur à un uid. Il se lit essentiellement comme "le nom d'utilisateur 'myname' appartient à 'some-user-uid'".

Avec cette structure de données, vos règles de sécurité peuvent vérifier s'il existe déjà une entrée pour un nom d'utilisateur donné:

"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"
    }
  }
}

Cela valide que le nom d'utilisateur n'est pas encore revendiqué par quiconque OR il est revendiqué par l'utilisateur actuel.

48
Frank van Puffelen

Enregistrez les noms d'utilisateur comme suggéré par Frank, mais lorsque vous enregistrez les noms d'utilisateur, utilisez la fonction runTransaction dans Firebase pour vous assurer que le nom d'utilisateur n'est pas pris. Cette fonction est garantie par Firebase comme une opération atomique afin que vous puissiez être assuré de ne pas avoir de collision

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
        }
    }
});
5
Viven