首页 文章

如何在firebase中管理用户的不同身份验证

提问于
浏览
2

请帮助我在以下情况下找到正确的解决方案 .

我正在使用swift开发ios应用程序,它将使用Firebase作为后端 .

用户应该能够使用电子邮件/密码或/和facebook登录firebase . 也许google将在稍后添加 .

对我来说,为每个真实用户设置一个firebase帐户非常重要,因为用户将获得奖励积分,如果在一个设备上(使用电子邮件登录)他将拥有X积分并且在其他设备上(使用facebook),这将是没有意义的 . 会有不同的观点 .

这是我用来登录电子邮件的代码:

//EMAIL REGISTER  
    @IBAction func registerAction(_ sender: Any) {

        if self.emailTextField.text == "" || self.passwordTextField.text == "" {

            Print( "Please enter email and password.")

        } else {

            FIRAuth.auth()?.createUser(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!, completion: { (user, error) in

                if error == nil {
                    self.logoutButton.isHidden = false
                    self.usernameLabel.text = user!.email
                    self.emailTextField.text = ""
                    self.passwordTextField.text = ""
                } else {
                    Print("\((error?.localizedDescription)!)")
                }

            } )

        }
    }

    //EMAIL LOGIN
    @IBAction func loginAction(_ sender: Any) {

        if self.emailTextField.text == "" || self.passwordTextField.text == "" {
            print( "Please enter email and password.")
        } else {

            FIRAuth.auth()?.signIn(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!, completion: { (user, error) in

                if error == nil {
                    self.logoutButton.isHidden = false
                    self.usernameLabel.text = user!.email
                    self.emailTextField.text = ""
                    self.passwordTextField.text = ""

                } else {

                    Print("\((error?.localizedDescription)!)")

                }
            })
        }
    }

这是我用来登录facebook的代码:

func loginButton(_ loginButton: FBSDKLoginButton!, didCompleteWith result: FBSDKLoginManagerLoginResult!, error: Error!) {

        self.fbLoginButton.isHidden = true

        if error != nil {

            self.fbLoginButton.isHidden = false
            print(error.localizedDescription)
            return

        } else if (result.isCancelled) {

            print("canceled")
            self.fbLoginButton.isHidden = false

        } else {

            let credential = FIRFacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)

            FIRAuth.auth()?.signIn(with: credential) { (user, error) in
                if let error = error {
                    print(error.localizedDescription)
                    return
                }
            }
        }
    }

两种方法都可以正常工作,但它们创建了两个独立的帐

它设置为允许多个用户在设置中使用相同的电子邮件:
enter image description here

我最终得到以下结果:

enter image description here

显然我希望这两个帐户自动合并 .

Documentation描述了如何链接auth提供程序的方法,但是用户应该使用一种方法登录,并且只有在此之后才能链接帐户 . 如果您已拥有oauth凭证,则使用 linkWithCredential 方法 . 如果用户是在一台带有电子邮件的设备上创建的,那么如果他决定再次使用facebook登录其他设备,则无法使用 .


在以任何这些方式登录后, FIRAuth.auth()?.addStateDidChangeListener 服务显示第二个视图控制器,我正在使用数据库 .

override func viewDidLoad(){super.viewDidLoad()

let user = FIRAuth.auth()?.currentUser
let dat = user?.providerData

let email = user?.providerData[0].email
let name = user?.displayName

if email != nil {
self.ref.child("user_profile").child("\(user!.uid)/email").setValue(email)
}

if name != {
self.ref.child("user_profile").child("\(user!.uid)/name").setValue(name)
}

}

假设我们使用facebook登录,也许有可能找到具有相同电子邮件的用户的UID并运行更新?如果有很多用户,不是很好的主意 .

其他想法是使用电子邮件作为ID如下:

self.ref.child("user_profile").child("\(email)/name").setValue(name)

不确定这是不是一个好选择?

谢谢你的回复 .

1 回答

  • 1

    如何在没有匿名用户的第一台设备上使用他的电子邮件和密码登录后,从不同设备登录用户 .

    创建用户后,您需要将电子邮件和密码保存为 NSUbiquitousKeyValueStore ,这样其他设备将可以访问电子邮件和密码,因为您需要先将用户登录才能将其帐户链接到Facebook,如下所示 .

    In FB console
    1.帐户电子邮件地址设置: Prevent creation of multiple accounts with the same email address 这样,如果用户已使用电子邮件地址登录,则不会再次创建帐户 .

    2.如果用户选择电子邮件地址作为首次登录:

    var iCloudKeyStore: NSUbiquitousKeyValueStore = NSUbiquitousKeyValueStore()
    
    FIRAuth.auth()?.createUser(withEmail: email, password: password) { (user, error) in
    
               // User created
                if error == nil{
    
                     // signed in successfully
    
                     //Save the password and the email. Or choose your way to save them
                     iCloudKeyStore.set(password, forKey: email)
    
    
                }else{
    
                    //Erorr
                }
            }
    
    • 现在用户在Firebase中有一个帐户,看起来像这样:

    enter image description here
    4.现在在另一台设备上,用户决定使用Facebook登录(不同的提供商)

    在您使用Facebook登录用户并拥有 FBSDKAccessTokenDidChange 通知的fb 's token: Usually inside the function's监听器后,您使用Facebook的令牌使用Firebase登录用户 .

    let credential = FIRFacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
    
        FIRAuth.auth()?.signIn(with: credential) { (user, error) in
            // ...
            if error != nil {
                // SETP 5. HERE
    
                let nsError = (error as! NSError)
                // Error: 17007 The email address is already in use by another account. ERROR_EMAIL_ALREADY_IN_USE
    
                 if nsError.code == 17007{
    
    
                        print(error,user?.uid,nsError.code,"facebook user error")
    
                        let email = nsError.userInfo["FIRAuthErrorUserInfoEmailKey"] as? String
                        self.signInUserWithEmail(email: email!)
                        print("email",email)
                    }
    
    
            }else{
    
    
                print(user!.uid,"facebook user login")
        }
    
    • 由于用户已拥有此电子邮件地址的帐户,他现在正尝试使用Facebook登录,因此会出现错误:正如您在步骤4中看到的那样,现在您需要在将帐户链接到Facebook之前登录用户:
    func signInUserWithEmail(email:String){
    
        let password = iCloudKeyStore.string(forKey: email)
    
    
        FIRAuth.auth()?.signIn(withEmail: email, password: password, completion: { (user:FIRUser?, error:Error?) in
    
    
            if user != nil{
    
                self.linkAccountWihtFacebook()
                print(user?.uid)
    
            }else{
    
                print(error?.localizedDescription)
            }
        })
    
    }
    

    func linkAccountWihtFacebook(){

    let credential = FIRFacebookAuthProvider.credential(withAccessToken: FBSDKAccessToken.current().tokenString)
    
            FIRAuth.auth()?.currentUser?.link(with: credential, completion: { (user:FIRUser?, error:Error?) in
    
                if let LinkedUser = user{
    
                    print("NEW USER:",LinkedUser.uid)
    
                }
    
                if let error = error as? NSError{
    
                    //Indicates an attempt to link a provider of a type already linked to this account.
                    if error.code == FIRAuthErrorCode.errorCodeProviderAlreadyLinked.rawValue{
                        print("FIRAuthErrorCode.errorCodeProviderAlreadyLinked")
                    }
    
                    //This credential is already associated with a different user account.
                    if error.code == 17025{
    
                    }
    
                    print("MyError",error)
                }
    
            })
    }
    
    • 这样,您将在Firebase控制台中获得以下结果:

    enter image description here

    Firebase documentation: https://firebase.google.com/docs/auth/ios/account-linking

    将身份验证提供程序凭据链接到用户帐户要将身份验证提供程序凭据链接到现有用户帐户:1 . 使用任何身份验证提供程序或方法登录用户 . 完成新身份验证提供程序的登录流程,但不包括调用FIRAuth.signInWith方法之一 . 例如,获取用户的Google ID令牌,Facebook访问令牌或电子邮件和密码 . 获取新身份验证提供程序的FIRAuthCredential

相关问题