2016-05-10 17 views
0

Ich erstelle eine App, die Firebases E-Mail- und Passwort-Login verwendet. Ich lasse den Benutzer sich mit einem Benutzernamen, einer E-Mail-Adresse und einem Passwort registrieren. Ich habe Probleme damit, den Benutzer daran zu hindern, erstellt zu werden, wenn der Benutzername nicht eindeutig ist. Ich habe andere Fragen (speziell Firebase-android-make-username-unique und how-prevent-username-from-duplicate-signup-infirebase) gelesen, aber ich habe es immer noch nicht vollständig funktionieren.Firebase iOS Swift: Doppelte Benutzernamen verhindern

folgte ich die Anweisungen in dem ersten Link oben und meine Datenstruktur als ein:

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

und meine Sicherheitsregeln wie:

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

Mit diesem Setup, wenn ich versuche zu erstellen Ein neuer Benutzer mit einem bereits vorhandenen Benutzernamen verhindert, dass der Benutzer meiner Datenstruktur hinzugefügt wird. Wenn der folgende Code aufgerufen wird, wird "Benutzerdaten konnten nicht gespeichert" gedruckt, wenn der Benutzername ein Duplikat ist.

func createNewAccount(uid: String, user: Dictionary<String, String>) { 

    USER_REF.childByAppendingPath(uid).setValue(user, withCompletionBlock: { 
     (error:NSError?, ref:Firebase!) in 
     if (error != nil) { 
     print("User Data could not be saved.") 
     } else { 
     print("User Data saved successfully!") 
     } 
    }) 
    } 

    func addUsernameToUsernamePath (userData: Dictionary<String, String>) { 

    USERNAME_REF.updateChildValues(userData) 
    } 

Hier ist, wo ich feststecke. Meine create account -Methode ruft die oben genannten zwei Methoden nicht auf, bis createUser und authUser aufgerufen werden (was ich brauche, um die UID zu erhalten). Mein Problem ist, dass der Benutzer immer noch als registrierter Benutzer erstellt wird und meine Sicherheitsregeln nur verhindern, dass die Benutzerinformationen zu meiner Datenstruktur hinzugefügt werden. Ich muss herausfinden, wie man den Benutzer daran hindert, erstellt zu werden, wenn es einen doppelten Benutzernamen gibt.

@IBAction func createAccount() { 
    let username = usernameField.text 
    let email = emailField.text 
    let password = passwordField.text 

    if username != "" && email != "" && password != "" { 

     // Set Email and Password for the New User. 

     DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in 

     if error != nil { 
      print("Error: \(error)") 
      if let errorCode = FAuthenticationError(rawValue: error.code) { 
      switch (errorCode) { 
      case .EmailTaken: 
       self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.") 
      default: 
       self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.") 
      } 
      } 

     } else { 

      DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: { 
      err, authData in 


      let user = ["provider": authData.provider!, "email": email!, "username": username!] 
      let userData = [username!: authData.uid!] 

      DataService.dataService.createNewAccount(authData.uid, user: user) 
      DataService.dataService.addUsernameToUsernamePath(userData)   

      }) 

EDIT

Hier ist meine aktualisierte create Methode, die mein Problem gelöst.

@IBAction func createAccount() { 
    let username = usernameField.text 
    let email = emailField.text 
    let password = passwordField.text 


if username != "" && email != "" && password != "" { 

    DataService.dataService.USERNAME_REF.observeEventType(.Value, withBlock: { snapshot in 
    var usernamesMatched = false 
    if snapshot.value is NSNull { 
     usernamesMatched = false 
    } else { 
     let usernameDictionary = snapshot.value 
     let usernameArray = Array(usernameDictionary.allKeys as! [String]) 
     for storedUserName in usernameArray { 
     if storedUserName == self.usernameField.text! { 
      usernamesMatched = true 
      self.signupErrorAlert("Username Already Taken", message: "Please try a different username") 
     } 
     } 
    } 

    if !usernamesMatched { 
     // Set Email and Password for the New User. 

     DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in 

     if error != nil { 
      print("Error: \(error)") 
      if let errorCode = FAuthenticationError(rawValue: error.code) { 
      switch (errorCode) { 
      case .EmailTaken: 
       self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.") 
      default: 
       self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.") 
      } 
      } 

     } else { 

      // Create and Login the New User with authUser 
      DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: { 
      err, authData in 


      let user = ["provider": authData.provider!, "email": email!, "username": username!] 
      let userData = [username!: authData.uid!] 

      // Seal the deal in DataService.swift. 
      DataService.dataService.createNewAccount(authData.uid, user: user) 
      DataService.dataService.addUsernameToUsernamePath(userData) 


      }) 
+0

Überprüfen Sie, dass der Benutzername vor dem Aufruf von createUser() nicht existiert? – Kato

+0

Danke für den Vorschlag. Ich habe gerade meinen Code aktualisiert und es scheint das Problem gelöst zu haben. – chickenparm

+0

Warum suchen Sie nicht zuerst nach dem doppelten Benutzernamen, über createUser-> FAuthenticationErrorEmailTaken, und wenn dieser verfügbar ist, erstellen Sie den Benutzer im Knoten/users? Wenn Sie dies tun, können Sie diesen Code auf wenige Zeilen reduzieren, da dieser Benutzername garantiert nicht in Ihrem/users-Knoten vorhanden ist. – Jay

Antwort

1

könnten Sie erlauben ohne einen gültigen Benutzernamen anmelden, und haben einen separaten „set username“ Bildschirm, dass Sie im Falle einer teilweisen Anmeldung zeigen.

Definieren Sie Ihre Sicherheitsregeln, um nach einem Nicht-Null-Benutzernamen zu suchen, bevor Sie Schreibvorgänge in anderen Teilen Ihrer Datenbank zulassen.

+0

Danke für den Vorschlag. Ich habe gerade einen Weg gefunden, es zu lösen, indem ich vor dem Aufruf von createUser() überprüfe, ob der Benutzername existiert. Ich schätze jedoch den Vorschlag und kann ihn implementieren, wenn ich mit meiner Lösung nicht zufrieden bin. – chickenparm

+0

Wahrscheinlich möchten Sie beides, andernfalls haben Sie eine Race Condition, wenn sich zwei Personen gleichzeitig für denselben Benutzernamen registrieren. –

+0

Guter Punkt.Ich habe gerade versucht, zwei Accounts mit demselben Benutzernamen auf zwei iPhones zu erstellen. Als ich zum selben Zeitpunkt create account berührte, stieß ich auf Probleme. – chickenparm

0

Ich konnte es durch Aktualisieren von createAccount() auf den Code unten funktioniert.

@IBAction func createAccount() { 
    let username = usernameField.text 
    let email = emailField.text 
    let password = passwordField.text 


    if username != "" && email != "" && password != "" { 

     // Checks for internet connection before saving the meetup. Returns if there is no internet connection. 
     let reachability = try! Reachability.reachabilityForInternetConnection() 

     if reachability.currentReachabilityStatus == .NotReachable { 
     let internetAlert = UIAlertController(title: "No Internet Connection", message: "Please make sure your device is connected to the internet.", preferredStyle: .Alert) 
     let internetAlertAction = UIAlertAction(title: "OK", style: .Default, handler: nil) 
     internetAlert.addAction(internetAlertAction) 
     presentViewController(internetAlert, animated: true, completion: nil) 
     return 
     } 
     DataService.dataService.USERNAME_REF.observeEventType(.Value, withBlock: { snapshot in 
     var usernamesMatched = false 
     if snapshot.value is NSNull { 
      usernamesMatched = false 
     } else { 
      let usernameDictionary = snapshot.value 
      let usernameArray = Array(usernameDictionary.allKeys as! [String]) 
      for storedUserName in usernameArray { 
      if storedUserName == self.usernameField.text! { 
       usernamesMatched = true 
       self.signupErrorAlert("Username Already Taken", message: "Please try a different username") 
      } 
      } 
     } 

     if !usernamesMatched { 
      // Set Email and Password for the New User. 

      DataService.dataService.BASE_REF.createUser(email, password: password, withValueCompletionBlock: { error, result in 

      if error != nil { 
       print("Error: \(error)") 
       if let errorCode = FAuthenticationError(rawValue: error.code) { 
       switch (errorCode) { 
       case .EmailTaken: 
        self.signupErrorAlert("Email In Use", message: "An account has already been created for this email address.") 
       default: 
        self.signupErrorAlert("Oops!", message: "Having some trouble creating your account. Please try again or check your internet connection.") 
       } 
       } 

      } else { 

       // Create and Login the New User with authUser 
       DataService.dataService.BASE_REF.authUser(email, password: password, withCompletionBlock: { 
       err, authData in 


       let user = ["provider": authData.provider!, "email": email!, "username": username!] 
       let userData = [username!: authData.uid!] 

       // Seal the deal in DataService.swift. 
       DataService.dataService.createNewAccount(authData.uid, user: user) 
       DataService.dataService.addUsernameToUsernamePath(userData) 


       }) 
Verwandte Themen