2

I am trying to verify if the username the user entered has been taken. The code currently checks if the email is in use and creates the user if they don't exist. How can I make this read the database to see if the username is already taken?

FIRAuth.auth()?.createUser(withEmail: email!, password: password!) { (user, error) in
    if error?._code == (FIRAuthErrorCode.errorCodeInvalidEmail.rawValue)
    {
        var ref: FIRDatabaseReference!
        ref = FIRDatabase.database().reference()
        ref.child("Users").observeSingleEvent(of: FIRDataEventType.value, with: { (snapshot) in

            if snapshot.hasChild(name!){
                ref.child("users").child((user?.uid)!).setValue(["username": name])
                print("true rooms exist")
            } else {
                self.displayMyAlertMessage(userMessage: "Username already in use. Please choose another.")
                print("false room doesn't exist")
            }
        })
    } else {
        self.displayMyAlertMessage(userMessage: "Email already in use. Please see the login page.")
        return
    }
}
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
AlexGarlock
  • 96
  • 1
  • 10
  • hmm isn't this "as simple as" writing your database backend? You're referring to 'the' database, which one? Do you have any code written towards a permanent storage? – Yohst Dec 29 '16 at 22:22
  • I am using firebase so the database is already there. the code toward the storage is the ref.child art of the code. – AlexGarlock Dec 29 '16 at 22:40
  • This has been asked "a few times" before. See [these answers](http://stackoverflow.com/search?q=%5Bfirebase-database%5D%5Bios%5D+unique+username) or the [original answer from Kato](http://stackoverflow.com/questions/25294478/how-do-you-prevent-duplicate-user-properties-in-firebase) (for JavaScript, but the logic is the same for all platforms). – Frank van Puffelen Dec 29 '16 at 22:59
  • I understand but there have been updates and those other answers do not work anymore. – AlexGarlock Dec 29 '16 at 23:01

1 Answers1

4

The thing you can do is to create another child eg "takenUsernames", store all the usernames there. And like this you can check if user is taken or not even if user is not authenticated. You have to add rule into database also.

Database Rules:

"takenUsernames": {
        ".read": true,
        ".write": "auth != null",
        "$username": {
        ".validate": "!root.child('takenUsernames').hasChild($username)"
        }
      }

And in Swift you can do like this, where username is value from textField. It basically just takes the username and checks if this exists or not in the takenUsername child:

let usernamesRef = FIRDatabase.database().reference().child("takenUsernames")
                usernamesRef.child(username).observeSingleEvent(of: .value, with: { (snapshot) in
                    if snapshot.exists() {
                        //Username is already taken
                    } else {
                      //Username doesn't exist, do your stuff
}

Now every time you register user, you gotta add key value pair into the takenUsernames child. In my case, I do it like this:

usernamesRef.updateChildValues([username:uid])

I hope you get the idea.

Tarvo Mäesepp
  • 4,477
  • 3
  • 44
  • 92
  • I think the security rules need some more safety features. With the current security setting, a user can potentially overwrite other usernames than their own as well. – Jordi Bruin Dec 30 '16 at 22:13
  • I get the idea. Storing the usernames in two spots pretty much. Not sure how a user can overwrite other usernames when your doing a check if that username exists. Feel like I would be like playstation now and not let users change their username LOL – AlexGarlock Jan 02 '17 at 23:08
  • What if we want to achieve this before a user is first authenticated? – waseefakhtar Jul 08 '17 at 18:49