I want to verify users that sign in with email and password with a verification email in firebase.
this is my code:
#IBAction func Login(_ sender: Any) {
guard let email = txtUser.text, email != "",
let password = txtPass.text, password != ""
else {
AlertController.showAlert(self, title: "Missing Info", message: "Please fill out all required fields")
return
}
Auth.auth().signIn(withEmail: txtUser.text!, password: txtPass.text!, completion: { (authResult,error) in
if error != nil{
AlertController.showAlert(self, title: "Error", message: error!.localizedDescription)
} else if authResult != nil {
self.performSegue(withIdentifier: "SegueMode", sender: self)
}
})
}
Have you tried this
Auth.auth().sendSignInLink(toEmail:email,
actionCodeSettings: actionCodeSettings) { error in
// ...
if let error = error {
self.showMessagePrompt(error.localizedDescription)
return
}
// The link was successfully sent. Inform the user.
// Save the email locally so you don't need to ask the user for it again
// if they open the link on the same device.
UserDefaults.standard.set(email, forKey: "Email")
self.showMessagePrompt("Check your email for link")
// ...
}
Here is Function that i used in my project
(Note: Change according to your requirement!)
func loginUser() {
guard let email = txtUserName.text, let password = txtPassword.text else { return }
Auth.auth().signIn(withEmail: email, password: password, completion: { (user, error) in
if let error = error {
print(error.localizedDescription)
self.lblSuccess.isHidden = false
self.lblSuccess.textColor = UIColor.red
self.lblSuccess.text = "Invalid Credential Please Check Your Email and password"
}else if let user = Auth.auth().currentUser {
let listVC = self.storyboard?.instantiateViewController(withIdentifier: "UserListVC") as! UserListVC
print(user)
self.lblSuccess.isHidden = false
self.lblSuccess.textColor = UIColor.green
self.lblSuccess.text = "Login SuccessFully!!"
self.navigationController?.pushViewController(listVC, animated: true)
}
})
}
Related
With the help of detailed tutorials, I was able to create a registration form and an email login, including a Google login.
I ran into a number of issues where I needed a few things, firstly I can't find any relevant information on the web regarding creating unique usernames so that I can log in via them other than email.
The second problem: I need to create the simplest user page, where all the necessary information about the user would be located, such as: avatar, email and username, as well as the function to change the avatar and password.
At the moment my database looks like this:
enter image description here
LoginViewController:
#IBAction func loginTapped(_ sender: Any) {
// Create cleaned version of the text fields
let email = usernameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let password = passwordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
// Sign in in the user
Auth.auth().signIn(withEmail: email, password: password) { (result, error) in
if error != nil {
// Couldn't sign in
self.errorLabel.text = error!.localizedDescription
self.errorLabel.alpha = 1
}
else {
let homeViewController =
self.storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as?
UITabBarController
self.view.window?.rootViewController = homeViewController
self.view.window?.makeKeyAndVisible()
UserDefaults.standard.set("email", forKey: "email")
}
}
}
SignUpViewController:
#IBAction func signUpTapped(_ sender: Any) {
guard let password = passwordTextField.text, !password.isEmpty,
let confirm = confirmPasswordTextField.text, !confirm.isEmpty else {
showError(message: "Password field is empty.")
return
}
guard password == confirm else {
showError(message: "Passwords do not match.")
return
}
// Validate the fields
let error = validateFields()
if error != nil {
// There's somthing wrong with the field, show the error message
showError(message: error!)
}
else {
// Create cleaned versions of the data
let username = usernameTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let email = emailTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
let password = passwordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
//let confirmpassword = confirmPasswordTextField.text!.trimmingCharacters(in: .whitespacesAndNewlines)
// Create the user
Auth.auth().createUser(withEmail: email, password: password) { (result, err) in
// Check for errors
if err != nil {
// There was an error creating the user
self.showError(message: "Error creating user.")
}
else {
// User was created successfully, now store username and other data needed
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["username":username, "uid": result!.user.uid ]) {
(error) in
if error != nil {
// Show error message
self.showError(message: "Error saving user data.")
}
}
// Transition to the home screen
self.transitionToHome()
}
}
}
}
func showError(message:String) {
errorLabel.text = message
errorLabel.alpha = 1
}
func transitionToHome() {
let homeViewController =
storyboard?.instantiateViewController(identifier: Constants.Storyboard.homeViewController) as?
UITabBarController
view.window?.rootViewController = homeViewController
view.window?.makeKeyAndVisible()
}
If I missed any important information, I will be glad if you ask and I will provide everything to you!
Thank you very much in advance for your time!
Here is the code from sign up view controller
import UIKit
import Firebase
class SignUpViewController: UIViewController {
#IBOutlet weak var userNameTextField: UITextField!
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var errorLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
userNameTextField.backgroundColor = .clear
userNameTextField.layer.cornerRadius = 27
userNameTextField.layer.borderWidth = 1
userNameTextField.layer.borderColor = UIColor.systemGreen.cgColor
emailTextField.backgroundColor = .clear
emailTextField.layer.cornerRadius = 27
emailTextField.layer.borderWidth = 1
emailTextField.layer.borderColor = UIColor.systemGreen.cgColor
passwordTextField.backgroundColor = .clear
passwordTextField.layer.cornerRadius = 27
passwordTextField.layer.borderWidth = 1
passwordTextField.layer.borderColor = UIColor.systemGreen.cgColor
}
And here is the code that must be executed after pressing the sign up button, but if I fill in password and email but not the username it throws an error and it still saves the data without username and after I try to sign up with the same email it says that this email already exists, even though username was empty
#IBAction func signupPressed(_ sender: UIButton) {
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let e = error {
self.errorLabel.text = e.localizedDescription
} else if self.userNameTextField.text == "" || self.userNameTextField.text!.count <= 3 {
self.errorLabel.text = "Please enter a valid username"
} else {
//Navigate to the ChatViewController
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["username": self.userNameTextField.text!, "uid": authResult!.user.uid]) { (error) in
if let e = error {
self.errorLabel.text = e.localizedDescription
}
}
self.performSegue(withIdentifier: "goToMap", sender: self)
}
}
}
}
}
You are checking for a username after you have created an account for the user, this is why you have an account regardless of having a username.
You should probably check that the username exists before creating the account. Using a guard let would allow you to check the username matches your criteria.
#IBAction func signupPressed(_ sender: UIButton) {
// check that the username exists and that it is of a valid length
guard let username = self.userNameTextField.text, username.count > 3 else {
self.errorLabel.text = "Please enter a valid username"
return
}
if let email = emailTextField.text, let password = passwordTextField.text {
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let e = error {
self.errorLabel.text = e.localizedDescription
} else {
//Navigate to the ChatViewController
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["username": username, "uid": authResult!.user.uid]) { (error) in
if let e = error {
self.errorLabel.text = e.localizedDescription
}
}
// This will navigate the user regardless of whether the
// database update was successful or not.
// You may want to reconsider this, and handle it in the above closure.
self.performSegue(withIdentifier: "goToMap", sender: self)
}
}
}
}
You also do not show any checks for email or password. You may wish to consider adding them as well. This is how I would fully refactor your code with checks for email and password, plus moving the performSegue call so that it only occurs if you do not get an error from adding the username.
#IBAction func signupPressed(_ sender: UIButton) {
// check that the username exists and that it is of a valid length
guard let username = self.userNameTextField.text, username.count > 3 else {
self.errorLabel.text = "Please enter a valid username"
return
}
guard let password = passwordTextField.text else {
self.errorLabel.text = "Please enter a valid password"
return
}
guard let email = emailTextField.text else {
self.errorLabel.text = "Please enter a valid email"
return
}
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let e = error {
self.errorLabel.text = e.localizedDescription
} else {
//Navigate to the ChatViewController
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["username": username, "uid": authResult!.user.uid]) { (error) in
if let e = error {
// You may not want to show this error to the user but you should still show a "sanitised" error so that it doesn't leak information.
self.errorLabel.text = e.localizedDescription
} else {
self.performSegue(withIdentifier: "goToMap", sender: self)
}
}
}
}
}
In the code if let email = emailTextField.text, let password = passwordTextField.text you are checking if the string reference is not nil. You also want to know if this string is not equal to "".
In this case, we can use the convenience getter: isEmpty.
Final code example:
#IBAction func signupPressed(_ sender: UIButton) {
if let email = emailTextField.text, let password = passwordTextField.text {
guard !email.isEmpty, !password.isEmpty else { return }
Auth.auth().createUser(withEmail: email, password: password) { authResult, error in
if let e = error {
self.errorLabel.text = e.localizedDescription
} else if self.userNameTextField.text == "" || self.userNameTextField.text!.count <= 3 {
self.errorLabel.text = "Please enter a valid username"
} else {
//Navigate to the ChatViewController
let db = Firestore.firestore()
db.collection("users").addDocument(data: ["username": self.userNameTextField.text!, "uid": authResult!.user.uid]) { (error) in
if let e = error {
self.errorLabel.text = e.localizedDescription
}
}
self.performSegue(withIdentifier: "goToMap", sender: self)
}
}
}
}
}
When creating a new user, I need to log them out and then send a verification email to ensure that they own the email address. Currently my code creates the user and executes the "sendEmailVerification" call but keeps the user logged in. How can I log my user out and check that they have verified their email?
func signUp(with email: String, password: String, firstName: String, lastName: String) {
self.presentActivityView()
Auth.auth().createUser(withEmail: email, password: password) {[unowned self] (user, error) in
DispatchQueue.main.async { [unowned self] in
self.dismissActivityView()
if let err = error {
self.addAlertController(title: "Error!", message: err.localizedDescription)
} else {
let changeReq = Auth.auth().currentUser?.createProfileChangeRequest()
changeReq?.displayName = firstName + " " + lastName
if let url = self.profilePicURLString {
changeReq?.photoURL = URL(string: url)
}
changeReq?.commitChanges(completion: { (error) in
if error == nil {
//Profile updated successfully
}else {
//Profile not updated successfully
}
})
Auth.auth().currentUser?.sendEmailVerification(completion: { (error) in
if error == nil {
//Verification initiated successfully
}else {
print("Error: \(error)")
}
})
let vc = MainStoryboard.instantiateViewController(withIdentifier: "SNStoryFeedController") as! SNStoryFeedController
let nc = UINavigationController(rootViewController: vc)
UIApplication.shared.keyWindow?.rootViewController = nc
}
}
}
}
The only thing you should do is sign out from your own application:
// for FIRAuth
try? Auth.auth()?.signOut()
// for GoogleSignIn
GIDSignIn.sharedInstance().signOut()
The safari part is handled by the system and you don't need to worry about.
I'm new in programming and still learning in swift language.
I hope you could help me with this issue.
when I try to signup the Userinfo shows in database but when I try to login the user info disappears why is that so? can't figure it out.
Here is how i signup
#objc func handleSignUp() {
guard let username = usernameField.text else { return }
guard let email = emailField.text else { return }
guard let pass = passwordField.text else { return }
guard let image = profileImageView.image else { return }
setContinueButton(enabled: false)
continueButton.setTitle("", for: .normal)
activityView.startAnimating()
Auth.auth().createUser(withEmail: email, password: pass) { user, error in
if error == nil && user != nil {
print("User created!")
// 1. Upload the profile image to Firebase Storage
self.uploadProfileImage(image) { url in
if url != nil {
let changeRequest = Auth.auth().currentUser?.createProfileChangeRequest()
changeRequest?.displayName = username
changeRequest?.photoURL = url
changeRequest?.commitChanges { error in
if error == nil {
print("User display name changed!")
self.saveProfile(username: username, profileImageURL: url!) { success in
if success {
self.dismiss(animated: true, completion: nil)
} else {
self.resetForm()
}
}
} else {
print("Error: \(error!.localizedDescription)")
self.resetForm()
}
}
} else {
self.resetForm()
}
}
} else {
self.resetForm()
}
}
}
And here is how I log in
#objc func handleSignIn() {
guard let email = emailField.text else { return }
guard let pass = passwordField.text else { return }
setContinueButton(enabled: false)
continueButton.setTitle("", for: .normal)
activityView.startAnimating()
Auth.auth().signIn(withEmail: email, password: pass) { user, error in
if error == nil && user != nil {
self.dismiss(animated: false, completion: nil)
_ = Auth.auth().currentUser
} else {
print("Error logging in: \(error!.localizedDescription)")
self.resetForm()
}
}
I don't know what seems to be the problem
I'm not familiar with firebase but according to their documentation this is "da way" :
Auth.auth().signIn(withEmail: email, password: password) { (user, error) in
if let error = error {
print("ERROR [ signIn ] => \(error)")
// self.resetForm()
} else {
if let user = user {
let uid = user.uid
let email = user.email
print("Authorised User => \(uid) ... \(email)")
}
}
}
If after trying the above code and you see this output ERROR [ signIn ] => whatever error...", then it's your signIn that failed. If you see this output Authorised User => SomeUID ... SomeEMAIL, then you signed in successfully and your user's data is still in the database.
I hope this helps you find "da way"
If all else fails:
You can change browsers and check your database again ? Try a couple of browsers. This worked for some people
Good luck!
I've been trying to figure this problem out for a few days and can't seem to find a solution that works.
The problem is: When I try to create an account in my app, it automatically creates an account without entering any information. So basically the user puts no info and the account is still being created.
I'm currently using Firebase
Here is the code for that View:
import UIKit
import Firebase
class createAccountVC: UIViewController {
private let RIDER_SEGUE = "createAccountSegue"
#IBOutlet weak var emailTextField: UITextField!
#IBOutlet weak var passwordTextField: UITextField!
#IBOutlet weak var confirmPasswordTextField: UITextField!
#IBOutlet weak var createAccountButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
createAccountButton.titleLabel?.numberOfLines = 2
createAccountButton.titleLabel?.lineBreakMode = NSLineBreakMode.byWordWrapping
}
private func alertTheUser(title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(ok)
present(alert, animated: true, completion: nil)
}
#IBAction func signUp(_ sender: AnyObject) {
if emailTextField.text != "" && passwordTextField.text != "" && confirmPasswordTextField.text != "" {
AuthProvider.Instance.signUp(withEmail: emailTextField.text!, password: passwordTextField.text!, loginHandler: { (message) in
if message != nil {
self.alertTheUser(title: "Problem with creating a new user.", message: message!)
} else {
GroomrHandler.Instance.rider = self.emailTextField.text!
self.saveUserInfo(email: self.emailTextField.text!, password: self.passwordTextField.text!)
self.emailTextField.text = ""
self.passwordTextField.text = ""
self.confirmPasswordTextField.text = ""
//self.performSegue(withIdentifier: self.RIDER_SEGUE, sender: nil)
// save password to keychain
}
})
} else {
alertTheUser(title: "Email and password are required.", message: "Please enter email and password in the text fields.")
}
}
func saveUserInfo(email: String, password: String) {
//save login info in app
UserDefaults.standard.set(email, forKey: "email")
}
}
Thank you in advance! Don't flame me, I'm still learning XD
EDIT: Here is the AuthProvider File:
import Foundation
import Firebase
typealias LoginHandler = (_ msg: String?) -> Void
struct LoginErrorCode {
static let INVALID_EMAIL = "Invalid email address, please provide a real email address."
static let WRONG_PASSWORD = "Wrong password, please enter the correct password."
static let PROBLEM_CONNECTING = "Problem connecting to database, please try later."
static let USER_NOT_FOUND = "User not found, please register."
static let EMAIL_ALREADY_IN_USE = "Email already in use, please use another email."
static let WEAK_PASSWORD = "Password should be at least 6 characters long."
}
class AuthProvider {
private static let _instance = AuthProvider()
static var Instance: AuthProvider {
return _instance
}
func login(withEmail: String, password: String, loginHandler: LoginHandler?) {
Auth.auth().signIn(withEmail: withEmail, password: password, completion: { (user, error) in
if error != nil {
self.handleErrors(err: error! as NSError, loginHandler: loginHandler)
} else {
loginHandler?(nil)
}
})
} // login func
func signUp(withEmail: String, password: String, loginHandler: LoginHandler?) {
Auth.auth().createUser(withEmail: withEmail, password: password, completion: { (user, error) in
if error != nil {
self.handleErrors(err: error! as NSError, loginHandler: loginHandler)
} else {
if user?.uid != nil {
// login the user
self.login(withEmail: withEmail, password: password, loginHandler: loginHandler)
}
}
})
} // sign up func
func logOut() -> Bool {
if Auth.auth().currentUser != nil {
do {
try Auth.auth().signOut()
return true
} catch {
return false
}
}
return true
}
private func handleErrors(err: NSError, loginHandler: LoginHandler?) {
if let errCode = AuthErrorCode(rawValue: err.code) {
switch errCode {
case .wrongPassword:
loginHandler?(LoginErrorCode.WRONG_PASSWORD)
break
case .invalidEmail:
loginHandler?(LoginErrorCode.INVALID_EMAIL)
break
case .userNotFound:
loginHandler?(LoginErrorCode.USER_NOT_FOUND)
break
case .emailAlreadyInUse:
loginHandler?(LoginErrorCode.EMAIL_ALREADY_IN_USE)
break
case .weakPassword:
loginHandler?(LoginErrorCode.WEAK_PASSWORD)
break
default:
loginHandler?(LoginErrorCode.PROBLEM_CONNECTING)
break
}
}
}
} // class
I had some experience in registering users, here is my code, you may try it. Hope that it helps.
This in User object:
Auth.auth().createUser(withEmail: email, password: password, completion: { (user, error) in
if error == nil {
user?.sendEmailVerification(completion: nil)
let storageRef = Storage.storage().reference().child("usersProfilePics").child(user!.uid)
let imageData = UIImageJPEGRepresentation(profilePic, 0.1)
storageRef.putData(imageData!, metadata: nil, completion: { (metadata, err) in
if err == nil {
let path = metadata?.downloadURL()?.absoluteString
let values = ["name": withName, "email": email, "profilePicLink": path!]
Database.database().reference().child("users").child(userType).child((user?.uid)!).child("credentials").updateChildValues(values, withCompletionBlock: { (errr, _) in
if errr == nil {
let userInfo = ["email" : email, "password" : password, "type" : userType]
UserDefaults.standard.set(userInfo, forKey: "userInformation")
completion(true)
}
})
}
})
}
else {
completion(false)
}
})
Here I am calling method of User object:
User.registerUser(withName: self.registerNameField.text!, email: self.registerEmailField.text!, password: self.registerPasswordField.text!, profilePic: self.profilePicView.image!, forUserType: UserType.psychologist) { [weak weakSelf = self] (status) in
DispatchQueue.main.async {
weakSelf?.showLoading(state: false)
for item in self.inputFields {
item.text = ""
}
if status == true {
weakSelf?.pushTomainView()
weakSelf?.profilePicView.image = UIImage.init(named: "profile pic")
} else {
for item in (weakSelf?.waringLabels)! {
item.isHidden = false
}
}
}
}
var abcd: String?
if abcd != "" {
print("hello")
}
The above code prints hello in the console. Similar issue is happening in your code. condition abcd != "" only test for empty, not nil. You should first unwrap all textfield text, then check for isEmpty, and create account.
#IBAction func signUp(_ sender: AnyObject) {
guard let email = emailTextField.text,
let password = passwordTextField.text,
let confirmPassword = confirmPasswordTextField.text,
email != "",
password != "",
confirmPassword != "" else {
alertTheUser(title: "Email and password are required.", message: "Please enter email and password in the text fields.")
}
AuthProvider.Instance.signUp(withEmail: email, password: password, loginHandler: { (message) in
if message != nil {
self.alertTheUser(title: "Problem with creating a new user.", message: message!)
} else {
GroomrHandler.Instance.rider = email
self.saveUserInfo(email: email, password: password)
self.emailTextField.text = ""
self.passwordTextField.text = ""
self.confirmPasswordTextField.text = ""
//self.performSegue(withIdentifier: self.RIDER_SEGUE, sender: nil)
// save password to keychain
}
})
}