You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现仅邮箱验证通过后才创建用户并禁止未验证用户登录

Got it, let's tackle this problem head-on. The main issue right now is that Firebase Auth creates the user account immediately, and your app lets un-verified users access the main screen on restart—even though you haven't added them to your database yet. Here's how to fix this so users only get added to the database after verifying their email, and can't access the app until they do:

Step 1: Adjust the Registration Flow

We'll still create the Firebase Auth user and send the verification email, but we'll hold off on writing user data to your database until the email is verified. We'll also pass user details (name, country) through the timer's userInfo so we can use them later.

var verificationTimer = Timer()

@objc func signupButtonPressed() {
    // Guard against empty fields with cleaner syntax
    guard let name = name.text, !name.isEmpty,
          let email = email.text, !email.isEmpty,
          let password = password.text, !password.isEmpty,
          let country = countryTextField.text, !country.isEmpty else {
        let emptyFieldAlert = UIAlertController(title: "Error", message: "Please fill out all the fields.", preferredStyle: .alert)
        emptyFieldAlert.addAction(UIAlertAction(title: "Ok", style: .cancel))
        present(emptyFieldAlert, animated: true)
        return
    }
    
    // Create Auth user first, but don't write to database yet
    Auth.auth().createUser(withEmail: email, password: password) { [weak self] result, error in
        guard let self = self else { return }
        
        if let error = error {
            print("Signup failed: ", error.localizedDescription)
            let errorAlert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert)
            errorAlert.addAction(UIAlertAction(title: "Ok", style: .cancel))
            self.present(errorAlert, animated: true)
            return
        }
        
        // Send verification email
        Auth.auth().currentUser?.sendEmailVerification(completion: { emailError in
            if let emailError = emailError {
                print("Failed to send verification email: ", emailError.localizedDescription)
            }
        })
        
        // Start timer to check verification status, pass user details via userInfo
        self.verificationTimer = Timer.scheduledTimer(
            timeInterval: 1,
            target: self,
            selector: #selector(self.checkIfEmailIsVerified),
            userInfo: ["name": name, "country": country],
            repeats: true
        )
    }
}

Step 2: Update Verification Check to Write to Database

Once the user verifies their email, we'll stop the timer, write their details to your database, then navigate to the main screen.

@objc func checkIfEmailIsVerified() {
    guard let currentUser = Auth.auth().currentUser else {
        verificationTimer.invalidate()
        return
    }
    
    currentUser.reload { [weak self] error in
        guard let self = self else { return }
        
        if let error = error {
            print("Failed to reload user data: ", error.localizedDescription)
            return
        }
        
        if currentUser.isEmailVerified {
            self.verificationTimer.invalidate()
            
            // Extract user details from timer's userInfo
            let userName = self.verificationTimer.userInfo?["name"] as? String ?? ""
            let userCountry = self.verificationTimer.userInfo?["country"] as? String ?? ""
            
            // Prepare data for your database (adjust for Firestore, Realtime DB, etc.)
            let userData: [String: Any] = [
                "uid": currentUser.uid,
                "name": userName,
                "email": currentUser.email ?? "",
                "country": userCountry,
                "createdAt": Date()
            ]
            
            // Write to database (example uses Firestore)
            let db = Firestore.firestore()
            db.collection("users").document(currentUser.uid).setData(userData) { dbError in
                if let dbError = dbError {
                    print("Failed to save user to database: ", dbError.localizedDescription)
                } else {
                    // Navigate to main screen only after successful database write
                    let mainPage = MainScreen()
                    self.present(mainPage, animated: true)
                }
            }
        }
    }
}

Step 3: Block Un-Verified Users on App Restart

Update your authentication check to not only verify if a user exists, but also if their email is verified. If not, prompt them to verify or log out.

func authenticateUserAndConfigure() {
    guard let currentUser = Auth.auth().currentUser else {
        DispatchQueue.main.async {
            self.present(LoginScreen(), animated: false)
        }
        return
    }
    
    // Reload user to get the latest verification status (local cache might be outdated)
    currentUser.reload { [weak self] error in
        guard let self = self else { return }
        
        if let error = error {
            print("Failed to reload user: ", error.localizedDescription)
            DispatchQueue.main.async {
                self.present(LoginScreen(), animated: false)
            }
            return
        }
        
        if !currentUser.isEmailVerified {
            // Show prompt for un-verified users
            let verificationAlert = UIAlertController(
                title: "Email Not Verified",
                message: "Please verify your email to access the app. We've sent a verification link to your inbox.",
                preferredStyle: .alert
            )
            
            verificationAlert.addAction(UIAlertAction(title: "Resend Verification", style: .default, handler: { _ in
                currentUser.sendEmailVerification(completion: { resendError in
                    if let resendError = resendError {
                        print("Failed to resend verification: ", resendError.localizedDescription)
                    } else {
                        let successAlert = UIAlertController(title: "Email Sent", message: "Check your inbox for the verification link.", preferredStyle: .alert)
                        successAlert.addAction(UIAlertAction(title: "Ok", style: .cancel))
                        self.present(successAlert, animated: true)
                    }
                })
            }))
            
            verificationAlert.addAction(UIAlertAction(title: "Logout", style: .destructive, handler: { _ in
                do {
                    try Auth.auth().signOut()
                    DispatchQueue.main.async {
                        self.present(LoginScreen(), animated: false)
                    }
                } catch {
                    print("Logout failed: ", error.localizedDescription)
                }
            }))
            
            DispatchQueue.main.async {
                self.present(verificationAlert, animated: true)
            }
        } else {
            // Optional: Double-check if user exists in your database before proceeding
            let db = Firestore.firestore()
            db.collection("users").document(currentUser.uid).getDocument { snapshot, dbError in
                if dbError != nil || snapshot?.exists == false {
                    print("User not found in database")
                    // Handle edge case (e.g., sign out user)
                } else {
                    // User is verified and exists in database: proceed to main app
                    DispatchQueue.main.async {
                        // Your main screen setup logic here
                    }
                }
            }
        }
    }
}

Key Notes

  • We use [weak self] in closures to avoid memory leaks.
  • The timer's userInfo safely passes user details from the registration flow to the verification check.
  • Reloading the user on app start ensures we get the latest verification status (Firebase caches this locally, so it might be stale).

内容的提问来源于stack exchange,提问作者Abdullah Ajmal

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:27:58