Firebase android: haz que el nombre de usuario sea único


Parse se cerrará a finales de año, así que decidí empezar a usar Firebase. Necesito implementar un proceso de registro con 3 campos: correo electrónico, nombre de usuario, contraseña ( El correo electrónico y el nombre de usuario deben ser únicos para mi aplicación).

Dado que Firebase no proporciona una manera fácil de administrar el nombre de usuario como Parse, decidí usar solo el registro de correo electrónico/contraseña y guardar algunos datos adicionales como nombre de usuario. Aquí está la estructura de datos de mis usuarios:

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

Pero, lo que quiero hacer es hacer que el nombre de usuario sea único y verificarlo antes de crear una cuenta. Estas son mis reglas :

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

Muchas Gracias por su ayuda

Author: FloGz, 2016-02-06

3 answers

Parte de la respuesta es almacenar un índice de nombres de usuario, que se comprueba en sus reglas de seguridad:

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

Así que el nodo usernames asigna un nombre de usuario a un uid. Esencialmente se lee como "username' myname 'es propiedad de' some-user-uid'".

Con esta estructura de datos, sus reglas de seguridad pueden verificar si ya hay una entrada para un nombre de usuario determinado:

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

Esto valida que el nombre de usuario no sea reclamado por nadie todavía O que sea reclamado por el usuario actual.

 41
Author: Frank van Puffelen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-06 18:22:34

Guarde los nombres de usuario como sugiere Frank, pero cuando guarde los nombres de usuario, use la función runTransaction en Firebase para asegurarse de que el nombre de usuario no esté tomado. Esta función está garantizada por Firebase para ser una operación atómica por lo que puede estar seguro de que no hay colisión

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
        }
    }
});
 3
Author: Viven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-28 01:49:00

Todavía no sé mucho sobre la seguridad de firebase, pero puede que haya resuelto el problema usando Java. Lo he publicado a continuación.

Mi estructura de datos es

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];
    }
 -3
Author: SJSU Software Engineer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-21 10:33:28