已验证用户访问主页,未验证用户留在登录状态

Verified users access home and unverified users stay in the login

我正在检查用户在登录功能中注册后是否收到验证邮件:

static func authenticate(withEmail email :String,
                         password:String,
                         completionHandler:@escaping (Result<Bool, EmailAuthError>) -> ()) {
    Auth.auth().signIn(withEmail: email, password: password) { (authResult, error) in
        // check the NSError code and convert the error to an AuthError type
        var newError:NSError
        if let err = error {
            newError = err as NSError
            var authError:EmailAuthError?
            switch newError.code {
            case 17009:
                authError = .incorrectPassword
            case 17008:
                authError = .invalidEmail
            case 17011:
                authError = .accoundDoesNotExist
            default:
                authError = .unknownError
            
            }
            completionHandler(.failure(authError!))
        } else {
            if (Auth.auth().currentUser!.isEmailVerified == true){
            completionHandler(.success(true))
                print ("Email Verified")
            }
            else {
                print ("Email not verified")
            }
        }
    }
}

单击“登录”按钮后将调用此函数,我在此处重新加载用户以确保 (isEmailVerified) 值已更新。

Button(action: {
            //Sign In Action
            FBAuth.reloadUser()
            FBAuth.authenticate(withEmail: self.user.email, password: self.user.password) { (result) in
                switch result {
                case .failure(let error):
                    self.authError = error
                    self.showAlert = true
                case .success( _):
                    print ("Signed in.")
                }
            }
         
        }

我正在检查用户登录状态的内容视图,我在将 isEmailVerified 添加到我的代码后没有更新它,因为我只有三种情况未定义,已签名,已签名,我不知道如何退出这个盒子的:

struct ContentView: View {
@EnvironmentObject var userInfo : UserInfo
@State var shouldShowSignUp : Bool = false
var body: some View {
    Group {
      if shouldShowSignUp {
       SignupView()
        }
      else  {
        ZStack{
if userInfo.isUserAuthenticated == .undefined{ SignupView()}
else if userInfo.isUserAuthenticated == .signedIn && Auth.auth().currentUser!.isEmailVerified == true {HomeView()} 
else if userInfo.isUserAuthenticated == .signedIn && Auth.auth().currentUser!.isEmailVerified == false {LoginView()}
          
      SplashScreen()
            }
        }
    }
    
    .onAppear {
        self.userInfo.configureFirebaseStateDidChange()
    }
}}

用户信息:

import Foundation
import FirebaseAuth

class UserInfo : ObservableObject{
enum FBAuthState{
    case undefined, signedOut, signedIn
}
@Published var isUserAuthenticated : FBAuthState = .undefined
@Published var user : FBUser = .init(uid: "", name: "", email: "")

var authStateDidChangeListenerHandle : AuthStateDidChangeListenerHandle?

func configureFirebaseStateDidChange (){
    authStateDidChangeListenerHandle = Auth.auth().addStateDidChangeListener({ (_,user) in
        guard let _ = user else {
            self.isUserAuthenticated = .signedOut
            return
        }
        self.isUserAuthenticated = .signedIn

    })
    
}
 
}

一切顺利。我得到了 isEmailVerified 的正确值。我的问题是如何让经过验证的用户访问 homeView 和未经验证的用户,他们会收到他们的电子邮件需要验证的警报,并且他们会留在 loginView 中。

因为你没有post你的观点,所以我必须用一个抽象的答案来回答。

在您的主 App 结构中

@main
struct TestApp1App: App {
    @Environment(\.scenePhase) private var scenePhase
    @AppStorage("emailVerified") private var emailVerified: Bool = false
    var body: some Scene {
        WindowGroup {
            if emailVerified{
                LoginView()
            }else{
                HomeView()
            }                
        }
    }
}

并且在您的登录视图中:

// Add this
@AppStorage("emailVerified") private var emailVerified: Bool = false

 Button(action: {
        //Sign In Action
        FBAuth.reloadUser()
        FBAuth.authenticate(withEmail: self.user.email, password: self.user.password) { (result) in
            switch result {
            case .failure(let error):
                self.authError = error
                self.showAlert = true
            case .success( _):
                print ("Signed in.")
                emailVerified = true //add this
            }
        }
     
  }

编辑:

但这并没有改变我回答的主要布局。例如,您不保留 verificationState。所以你必须重新做一遍。

在你的情况下,在你的应用程序结构中创建 UserInfo class 并检查 if 语句中的 isUserAuthenticated 属性。

编辑 2:

这可以通过多种方式简化。我的建议:

ContentView 应该是这样的:

struct ContentView: View {
    @EnvironmentObject var userInfo : UserInfo
    // pull the vars from persisted store this will also update your view when changed
    @AppStorage("authState") var authState: FBAuthState = .undefined
    @AppStorage("emailVerificationState") var emailVerificationState: Bool = false
    var body: some View {
        
        Group{
            if authState == .undefined || !emailVerificationState{
                SignupView()
            } else {
                ZStack{
                    if authState == .signedIn{
                        HomeView()
                    } else{
                        LoginView()
                    }
                    SplashScreen()
                }
            }
        }
        .onAppear {
            self.userInfo.configureFirebaseStateDidChange()
        }
    }
}

将您的用户信息更改为:

enum FBAuthState: Int{
    case undefined, signedOut, signedIn
}

class UserInfo : ObservableObject{
    
    @AppStorage("authState") var authState: FBAuthState = .undefined
    @Published var user : FBUser = .init(uid: "", name: "", email: "")
    
    var authStateDidChangeListenerHandle : AuthStateDidChangeListenerHandle?
    
    func configureFirebaseStateDidChange (){
        authStateDidChangeListenerHandle = Auth.auth().addStateDidChangeListener({ (_,user) in
            guard let _ = user else {
                self.authState = .signedOut
                return
            }
            self.authState = .signedIn
            
        })
        
    }
}

我不知道这个按钮在哪里,但在 class 或视图中添加:

@AppStorage("emailVerificationState") var emailVerificationState: Bool = false

并做:

Button(action: {
    //Sign In Action
    FBAuth.reloadUser()
    FBAuth.authenticate(withEmail: self.user.email, password: self.user.password) { (result) in
        switch result {
        case .failure(let error):
            emailVerificationState = false
            self.authError = error
            self.showAlert = true
        case .success( _):
            emailVerificationState = true
            print ("Signed in.")
        }
    }
    
}

编辑 3:

  • 您需要在要使用@AppStorage 属性 包装器的地方导入 SwiftUI 模块。
  • 请看我的回答。我将 FBAuthState 移出您的 class 以使其在外部可见。你需要从 Int.
  • 派生

编辑 4:

Group{
        if authState == .undefined {
            SignupView()
        } else {
            ZStack{
                if authState == .signedIn && emailVerificationState{
                    HomeView()
                } else{
                    LoginView()
                }
                SplashScreen()
            }
        }
    }