0

here is my situation for my iOS app ( I am using swift 3.0 and firebase).

I have a login screen, where the user are able to login via their E-mail using the Auth of firebase. For that I am using this code:

    @IBAction func signInButtonPressed(_ sender: UIButton)
{


    if let email = emailField.text, let password = passwordField.text
    {
      //  FIRDatabase.database().reference().child("users").child(self.emailField.text!).observeSingleEvent(of: .value, with: {(userEmail) in
       // FIRAuth.auth()?.signIn(withEmail: email, password: password)

        FIRAuth.auth()?.signIn(withEmail: email, password: password)
        {
            (user, error) in

            if let error = error
            {
                let alertController = UIAlertController(title: "Login or password incorrect", message:
                    "", preferredStyle: UIAlertControllerStyle.alert)
                alertController.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default,handler: nil))

                self.present(alertController, animated: true, completion: nil)                }
            else
            {
                print("AUTH: EMAIL AUTH SUCCESSFUL")

                User.currentUserId = user?.uid
                User.startTrackingCurrentUser()
                self.performSegue(withIdentifier: "ToFeed", sender: nil)
            }
        }
    }
}

Which is working perfectly !

What I'am trying to achieve, is instead to sign in user via their username. For that I believe the best thing is when recognising if the user exist, to send the email value instead - fetching the data from the DB.

My DB is configure correctly, and fetch the auth system such as:

--name of db
----posts
----users
------username
------email
------id

And I get the user recognise in my console when typing the correct username in the text field via:

@IBAction func textFieldEditingDidChange(_ sender: Any) {
    FIRDatabase.database().reference().child("users").child(self.emailField.text!).observeSingleEvent(of: .value, with: {(email) in

    if let userDict = email.value as? [String:AnyObject]{
        for each in userDict{
            let email = each.1 as! String
        }
    }

    if email.exists(){

        print(email)

    }else{

        print("USER NOT EXIST")

    }

})

}

I'm having display in my console the following when the username written is correct:

Snap (myuser) {
username = myuser;
email = "myemail@email.com";
id = 8mbwXUMe0Ye4ip2mhhvEySxmxiI5;

}

For this I have been following this thread:

Sign In by UserName : Firebase,Swift

From now, how can i on submit, use the email value from the snap instead of the username to be able to login ? I don't manage to make this work, I have been working on that for a week now . . .

Any help will be superb ! I'm starting on iOS Dev.

Thanks a lot !

---EDIT --

Now I'm managing to have only the email try print in my console via:

IBAction func textFieldEditingDidChange(_ sender: Any) {


    FIRDatabase.database().reference().child("users").child(self.emailField.text!).observeSingleEvent(of: .value, with: {(email) in

        if let userDict = email.value as? [String:AnyObject]{
   print(email)

        }

        if email.exists(){


        }else{

            print("USER NOT EXIST")

        }

    })
}

But still looking how to pass the value ?

tibewww
  • 593
  • 4
  • 11
  • 32
  • You are not going to want to do this. Trying to bypass the super easy to use built-in Firebase authentication will cause a lot of issues. You'll have to expose a users node so that anyone can read it to prevent duplicate user names, you'll write a lot of extra code to manage it, the email addresses that go with the username will also be exposed - which would allow those emails to fall into the hands of spammers. Stick with the built-in authentication! – Jay May 30 '17 at 16:51
  • in the front end no-one is able to register, so i suppose that it will not occur that, i heard it not the best way - but it is what i need unfortunately. DO you know how can i achieve it ? Thanks for your time ! – tibewww May 30 '17 at 16:53
  • I do, but it's not a good solution. You will need to create a node that contains user names and emails. That node will need to be queryable by an unauthenticated user, which means it's exposed to *anyone*. Once you query for the username, a node will be returned in the snapshot so you can get the email. If you really want to pursue this, the code is pretty simple. Again though, it's going to cause issues and you will go back to the built-in authentication at the end. – Jay May 30 '17 at 17:00
  • Thanks Jay, Yes i know it will cause those issues, but I'm desperate to make this work for a week now ( I'm starting on iOS dev). Would you mind to share if yo have any code which could fit with mine ?? Thanks a lot =) – tibewww May 30 '17 at 17:02

2 Answers2

0

You should get this email from snapshot and use it in signIn function:

FIRAuth.auth()!.signIn(withEmail: email, // your fetched email
                         password: userPassword.text!) { // userPassword is UITextField
                          user, error in
                          if error != nil {
                             // here process your error like
                             self.errorLabel.text = "Wrong login or password!"
                             print("\(String(describing: error?.localizedDescription))")
                          } else {
                             // you have signed in. Go to next controller
                             self.performSegue(withIdentifier: "fromLoggedInToTabBar", sender: self)
                          }
  }

Hope it helps

Vlad Pulichev
  • 3,162
  • 2
  • 20
  • 34
0

I want to stress that creating a username login system is strongly discouraged!

Let's start with a users node

user_email_lookup
  uid_0
    email: "johnny@dontdothis.com"
    user_name: "johnny_unsecure"
  uid_1
    email: "fred@exposednodes.com"
    user_name: "fred_stolendata"

the user_email_lookup node will provide the link between the user name the user entered and the email address of an authenticated user in Firebase. This node needs to have rules that allow anyone to access it - this is necessary as the queries on that node need to be done by an unauthenticated user. There's another structure option as well

user_email_lookup
  johnny_unsecure: "johnny@dontdothis.com"
  fred_stolendata: "fred@exposednodes.com"

But it will make managing user name and/or email changes later more difficult, so not recommended.

(again, don't do this, it's bad form)

Here are the base rules that need to apply the user_email_lookup

{
    "rules": {
        ".read": true,
        ".write": true
    }
}

(ugh; remember this node can be accessed by anyone. Don't do it!)

Assume that the app presents a screen where the user can type their user name and password, with a login button. Pressing the login button calls the beginLogin function as follows

func beginLogin() {
    let userName = "johnny_unsecure" //from the userNameField.text
    let password = "my_password" // from the passwordField.text

    let lookupRef = self.ref.child("user_email_lookup")
    let queryRef = lookupRef.queryOrdered(byChild: "user_name").queryEqual(toValue: userName)

    queryRef.observeSingleEvent(of: .childAdded, with: { snapshot in
        let dict = snapshot.value as! [String: Any]
        let email = dict["email"] as! String
        self.logUserIn(email: email, password: password)
    })
}


func logUserIn(email: String, password: String) {

    Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in 
        if error != nil {
            let err = error?.localizedDescription
            print(err)
        } else {
            print("succesfully authd")
            print(user)
        }
    })
}
Jay
  • 34,438
  • 18
  • 52
  • 81
  • Hi Jay, Thanks very much for those, very useful . . I'm aware of the security but unfortunately, it's what i need .. really appreciate your time ! On lien 2 + 3 of your code let userName = "johnny_unsecure" //from the userNameField.text let password = "my_password" // from the passwordField.text What do you mean by the .text file ? can it not call from firebase instead ? Thanks a lot ! – tibewww May 31 '17 at 09:00
  • IM having an error 'value of type 'signIn' has no member 'ref' on let lookupRef = self.ref.child("user_email_lookup") "signIn' being my 'screen code' – tibewww May 31 '17 at 09:40
  • got it working !! Awesome ! Really appreciated your help and time ! – tibewww May 31 '17 at 11:59