22

Parse zakończy się pod koniec roku, więc zdecydowałem się rozpocząć korzystanie z Firebase. Muszę zaimplementować proces rejestracji z 3 polami: e-mail, nazwa użytkownika, hasło (E-mail & nazwa użytkownika musi być unikalny dla mojej aplikacji).Firebase Android: utwórz nazwę użytkownika unikatową

Ponieważ Firebase nie zapewnia łatwego sposobu zarządzania nazwą użytkownika, taką jak Parse, postanowiłem użyć tylko rejestracji adresu e-mail/hasła i zapisać niektóre dodatkowe dane, takie jak nazwa użytkownika. Oto struktura danych użytkowników:

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

Ale chcę zrobić to, aby nazwa użytkownika była unikalna i sprawdzać ją przed utworzeniem konta. To są moje zasady:

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

Dziękuję bardzo za pomoc

+0

Więc chcesz zasady Firebase być sprawdzone na kliencie z systemem Android? –

+0

Tak, chcę najpierw sprawdzić, czy nazwa użytkownika zostanie podjęta, jeśli baza ogniowa powie mi, że nie, a następnie utworzyć konto, w przeciwnym razie po prostu poproś użytkownika o wybranie innej nazwy użytkownika – FloGz

+1

Oprócz odpowiedzi na pytanie dotyczące struktury danych i reguł bezpieczeństwa, oto kilka pytań, na których temat został zostały już wcześniej omówione: http://stackoverflow.com/questions/29970681/enforcing-unique-usernames-with-firebase-simplelogin, http://stackoverflow.com/questions/25294478/how-do-you-prevent-duplicate- user-properties-in-firebase, http://stackoverflow.com/questions/15910165/usernames-with-firebase-simple-login-email-password, http://stackoverflow.com/questions/20260476/what-firebase- reguła-zapobiegnie-duplikuje-w-kolekcji-na-innych-polach –

Odpowiedz

36

Część odpowiedzi jest przechowywanie indeks nazw użytkownika, sprawdzenie przed w swoich zasad bezpieczeństwa:

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

Węzeł usernames mapuje nazwę użytkownika na identyfikator użytkownika. Zasadniczo czyta się jako "nazwa-użytkownika" -nazwę "jest własnością" jakiegoś użytkownika-użytkownika ".

Dzięki tej strukturze danych, twoje zasady bezpieczeństwa może sprawdzić, czy istnieje już wpis dla danej nazwy użytkownika:

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

To potwierdza, że ​​nazwa użytkownika nie jest uważana przez nikogo jeszcze LUB twierdzi się przez aktualny użytkownik.

+1

świetna odpowiedź, duplikat z http://stackoverflow.com/questions/25294478/how-do-you-prevent-duplicate-user -properties-in-firebase – Creos

+4

Cześć Frank, myślę, że byłoby również ważne, aby zauważ, że powinieneś prawdopodobnie rzucić wszystkie kontrole na 'usernames' na małe litery i zapisać małe litery, w ten sposób nie będziesz mieć identycznych nazw użytkowników o różnej wielkości liter. Wartość przechowywana w polu 'users/some-user-uid/username' może być rozróżniana z uwzględnieniem wielkości liter, która może być wersją czytelną, co powinno pozwolić na bardziej przyjazny dla użytkownika wybór nazwy użytkownika i przestrzeganie przypadku. –

+0

@Frank van Puffelen Czy możesz potwierdzić, co Viv mówi na temat jego odpowiedzi na temat używania transekcji zamiast normalnego zestawu zapytań? A także, każde wyrażenie, które napisałeś wcześniej, może być użyte do sprawdzenia dozwolonych znaków dla nazw użytkowników? – Relm

-3

Nie wiem jeszcze wiele o bezpieczeństwie firebase, ale prawdopodobnie rozwiązałem problem za pomocą Javy. Opublikowalem to poniżej.

moja struktura danych jest

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

Zapisz nazwy użytkownika jako sugerowane przez Franka ale po zapisaniu nazwy użytkownika, należy użyć funkcji runTransaction w Firebase, aby upewnić się, że nazwa użytkownika nie jest brany. Funkcja ta jest gwarantowana przez Firebase być operacja atomowa więc możesz być pewny, bez kolizji

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 
     } 
    } 
}); 
+0

Ustawiasz go na liście nazw użytkowników, ale nie w uid. Czy powinniśmy dodać do tego pełną linię? – user2997154