【问题标题】:How to manage users' different authentication in firebase如何在firebase中管理用户的不同身份验证
【发布时间】:2016-12-29 07:39:51
【问题描述】:

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

我正在使用 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
                }
            }
        }
    }

这两种方法都可以正常工作,但它们会创建两个单独的帐户。

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

我最终得到以下结果:

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

Documentation 描述了如何链接身份验证提供者的方式,但用户应该使用一种方法登录,然后才能链接帐户。 linkWithCredential 如果您已经拥有 oauth 凭证,则使用方法。如果用户是使用电子邮件在一台设备上创建的,那么如果他决定使用 facebook 在另一台设备上再次登录,它将无法正常工作。


使用上述任何一种方式登录后,FIRAuth.auth()?.addStateDidChangeListener 服务将显示我正在使用数据库的第二个视图控制器。

覆盖 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)

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

感谢您的回复。

【问题讨论】:

    标签: ios swift firebase swift3 firebase-authentication


    【解决方案1】:

    如何在没有匿名用户的情况下使用他的电子邮件和密码在第一台设备上登录后从其他设备登录用户。

    创建用户后,您需要将电子邮件和密码保存到NSUbiquitousKeyValueStore,这样其他设备就可以访问电子邮件和密码,因为您需要先登录用户,然后才能将他们的帐户链接到 Facebook见下文。

    在 FB 控制台中
    1. 帐户电子邮件地址设置:防止使用相同的电子邮件地址创建多个帐户这样,如果用户已经使用电子邮件地址登录,则不会再次创建帐户。

    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
                }
            }
    
    1. 现在用户在 Firebase 中有一个帐户,看起来像这样:

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

    在您使用 Facebook 登录用户并拥有 fb 令牌后:通常在函数的 FBSDKAccessTokenDidChange Notification 侦听器中,您使用 Firebase 使用 Facebook 令牌登录用户。

    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")
        }
    
    1. 由于用户已经有一个使用此电子邮件地址的帐户,他现在正尝试使用 Facebook 登录,因此会发生错误:如您在第 4 步中看到的,现在您需要先登录用户,然后才能链接帐户到脸书:

      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)
                  }
      
              })
      }
      
    2. 这样您将在 Firebase 控制台中获得以下结果:

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

    将身份验证提供者凭据链接到用户帐户

    要将身份验证提供者凭据链接到现有用户帐户:

    1.使用任何身份验证提供程序或方法登录用户。

    1. 完成新身份验证提供程序的登录流程,直至调用 FIRAuth.signInWith 方法之一,但不包括调用。 例如,获取用户的 Google ID 令牌、Facebook 访问令牌,或 电子邮件和密码。
    2. 为新的身份验证提供程序获取 FIRAuthCredential

    【讨论】:

    • 您好,如果我选择阻止创建多个帐户...在我使用电子邮件和密码创建帐户后,我无法使用 Facebook 登录。 (因为电子邮件是相同的)。我使用的代码与您使用电子邮件和密码登录时所写的代码相同。还是我错过了什么?
    • 假设我已经有一个包含电子邮件和密码的帐户。我想在其他设备上使用 facebook 登录。我想登录现有用户而不是创建新用户。
    • 很高兴看到
    • 唯一的错误是在线 "guard FacebookManager.shared.isLoggedIN() == true" 未解析的标识符 FacebookManager
    • NSUbiquitiousKeyValueStore 中存储密码等敏感信息被视为安全漏洞。钥匙串(只有在用户需要时才将密码与 iCloud 同步)是唯一应该存储密码的地方。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-12-05
    • 2021-11-10
    • 1970-01-01
    • 2016-02-05
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多