如何在Firebase中管理用户的不同身份验证 [英] How to manage users' different authentication in firebase

查看:307
本文介绍了如何在Firebase中管理用户的不同身份验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

用户应该能够通过电子邮件/密码或/和Facebook登录到firebase。也许谷歌将在稍后添加。

对于每个真实用户拥有一个Firebase帐户是非常重要的,因为用户将获得奖励积分,并且不会有意义在一个设计(用电子邮件登录),他将有X点和其他设备(与脸谱),他将有不同的观点。

这是我正在使用的代码登录与电子邮件:

  // EMAIL REGISTER 
@IBAction FUNC registerAction(_发件人:任何){

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

打印(请输入电子邮件和密码)

} else {

FIRAuth。 AUTH()?的createUser(withEmail:self.emailTextField.text!密码:self.passwordTextField.text !,完成:{(用户,误差)在

如果错误== {零
self.logoutButton.isHidden =假
self.usernameLabel.text =用户!.email
self.emailTextField.text =
self.passwordTextField.text =
}其他{
打印( \((错误?.localizedDescription)!))
}

})

}
}

// EMAIL LOGIN
@IBAction FUNC则loginAction(_发件人:任何){

如果self.emailTextField.text == || self.passwordTextField.text =={
print(请输入电子邮件和密码)
} else {

FIRAuth.auth()?. signIn(withEmail :self.emailTextField.text!密码:self.passwordTextField.text!完成:{(用户,误差)

如果错误==零{
self.logoutButton.isHidden =假
self.usernameLabel.text =用户!.email
self.emailTextField.text =
self.passwordTextField.text =

}其他{

打印( \((错误?.localizedDescription)!))

}
})
}
$} b $ b

这里是我使用Facebook登录的代码:

  FUNC loginButton(_ loginButton:FBSDKLoginButton!didCompleteWith结果:FBSDKLoginManagerLoginResult!错误:错误!){

self.fbLoginButton.isHidden = TRUE

如果错误!= {零

self.fbLoginButton.isHidden =假
打印(error.localizedDescription)
返回

}否则,如果(result.isCancelled){

打印( 取消)
self.fbLoginButton.isHidden =假

}其他{

让凭证= FIRFacebookAuthProvider.credential(withAccessToken:FBSDKAccessToken.current()tokenString)

FIRAuth.auth()?签到(附:凭据) {(用户,误差)
如果让误差= {错误
打印(error.localizedDescription)
返回
}
}
}
}

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

设置为允许多个用户使用相同的电子邮件设置:
在这里输入的图像描述



我最终得到以下结果:
$ b

在这里输入的图像描述



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

文档 a>描述了如何链接auth提供程序,但用户应该使用一种方法登录,并且只有在这之后才能链接帐户。如果您已经拥有oauth凭证,则使用
linkWithCredential 方法。如果用户使用电子邮件在一台设备上创建,如果他决定再次登录其他设备上的Facebook,则无法工作。






与任何的这些方式的 FIRAuth.auth()?addStateDidChangeListener <洛后/ code>服务正在显示第二个视图控制器,我正在使用数据库。



倍率FUNC viewDidLoad中(){
super.viewDidLoad()



 让用户= FIRAuth.auth()?currentUser 
让DAT =用户?.providerData

让电子邮件=用户?.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像这样:
$ b $ p $ self_ref .child( user_profile)。子女( \(电子邮件)/名)。setValue方法(名称)



不知道这是一个很好的选择?

感谢您的回复。


解决方案

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



创建用户后,您需要保存到 NSUbiquitousKeyValueStore 这样的电子邮件和密码等设备将有访问电子邮件和密码,因为您需要先登录用户,然后再将其帐户链接到Facebook,如下所示。


$ b 在FB控制台

1.帐户电子邮件地址设置:防止使用相同电子邮件地址创建多个帐户这样,如果用户已经使用相同的电子邮件地址登录,则不会再次创建该帐户如果用户选择电子邮件地址作为第一次登录:

  VAR iCloudKeyStore:NSUbiquitousKeyValueStore = NSUbiquitousKeyValueStore()

FIRAuth.auth()?的createUser(withEmail:电子邮件,PAS剑:密码){(用户,错误)在

//用户创建
如果错误==无{

//成功登录

//保存密码和电子邮件。或者选择你的方式来保存它们
iCloudKeyStore.set(password,forKey:email)


} else {
$ b $ // // Erorr


$ / code $ / pre
$ b $ ol $ start $ =
  • 现在用户在火力地堡具有账户,并且将看起来像:



  • 在这里输入的图像描述
    4.现在在其他设备上,用户决定使用Facebook(不同的提供商)登录



    用Facebook登录用户并获得fb令牌后:函数的侦听器 FBSDKAccessTokenDidChange 通知,您使用Facebook的令牌在Firebase中登录用户。

     让凭证= FIRFacebookAuthProvider.credential(withAccessToken:FBSDKAccessToken.current()tokenString)

    FIRAuth .auth()?。signIn(with:credential){(user,error)in
    // ...
    if error!= nil {
    // SETP 5. HERE

    让nsError =(错误为!NSError)
    //错误:17007电子邮件地址已被另一个帐户使用。 ERROR_EMAIL_ALREADY_IN_USE

    如果nsError.code == 17007 {


    打印(错误,用户?.uid,nsError.code, Facebook的用户错误)

    让email = nsError.userInfo [FIRAuthErrorUserInfoEmailKey]为?字符串
    self.signInUserWithEmail(email:email!)
    print(email,email)
    }


    } else {

    $ b $ print(user!.uid,facebook用户登录)
    }




    1. 由于用户已经拥有了一个他正在用Facebook登录的邮箱地址,所以会出现错误:在步骤4,现在你需要您链接之前帐户Facebook在用户登录:

        FUNC signInUserWithEmail(电子邮件:字符串){

      让密码= iCloudKeyStore.string(forKey:电子邮件)


      FIRAuth.auth()?签到(withEmail:电子邮件,密码:密码,完成:{(用户:FIRUser?错误:错误)在


      如果用户=零{

      self.linkAccountWihtFacebook()
      ! print(user?.uid)

      } else {

      print(error?.loc alizedDescription)
      }
      })

      }

      FUNC linkAccountWihtFacebook(){

       让凭证= FIRFacebookAuthProvider.credential(withAccessToken:FBSDKAccessToken.current()tokenString)$ b $如果让LinkedUser = user {




      $ FIRAuth.auth()?currentUser?.link(with:credential,completion:{(user:FIRUser ?, error:Error?

      print(NEW USER:,LinkedUser.uid)

      }

      如果让error = error as? NSError {

      //表示尝试链接已经链接到此帐户的类型的提供者。如果
      error.code == FIRAuthErrorCode.errorCodeProviderAlreadyLinked.rawValue {
      打印( FIRAuthErrorCode.errorCodeProviderAlreadyLinked)
      }

      //这个证书已经与相关不同的用户帐户。
      if error.code == 17025 {

      }

      print(MyError,error)
      }

      }}
      }


    2. 这样,您将在Firebase控制台:




    3. 在这里输入的图像描述



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


      连结认证供应商凭证到用户帐户



      要将认证提供者凭证关联到现有用户帐户,请执行以下操作:

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


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

      2. 获取新身份验证提供程序的FIRAuthCredential



      please help me finding correct solution in the following situation.

      I am developing ios app with swift which will use Firebase as a backend.

      Users should be able to login into firebase with email/password or/and with facebook. Maybe google will be added later.

      It is important for me to have one firebase account for each real user as user will have reward points and it won't make sense if on one devise(with email login) he will have X points and on other device(with facebook) he will have different points.

      Here is code which I am using to login with email:

        //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)!)")
      
                      }
                  })
              }
          }
      

      Here is code which I am using to login with 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
                      }
                  }
              }
          }
      

      Both methods work fine, but they create two separate accounts.

      It is set up to allow multiple users with the same email in settings:

      and I end up with the following result:

      Obviously I want these two accounts to be merged automatically.

      Documentation describes the way how to link auth providers, but user should be logged in with one method and only after that it will be possible to link accounts. linkWithCredential method is used if you already have the oauth credential. In case user was created on one device with email it wont work if he will decide to login again on other device with facebook.


      After loggin in with any of these ways the FIRAuth.auth()?.addStateDidChangeListener service is showing second view controller where I am working with database.

      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)
      }
      

      }

      Let say we loggin with facebook, maybe it is possible to find UID of user with same email and run updates? Not very good idea in case there are a lot of users.

      Other idea is to use email as id like this:

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

      Not sure if it is a good option?

      thanks for your replies.

      解决方案

      How to sign in a user from different device after he signed in using he's email and password on the first device without anonymous users.

      After creating the user you need to save the email and password to NSUbiquitousKeyValueStore this way the other device will have access to email and password because you will need to sign in the user first before linking their account to Facebook as you will see below.

      In FB console
      1. Account Email address settings:Prevent creation of multiple accounts with the same email address This way the account doesn't get created again if the user already signed in with email address.

      2.If the user choose email address as first login:

       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. Now the user has an account in Firebase and will look like that:

      4. Now on the other device the user decided to login with Facebook (different provider)

      After you have signed in the user with Facebook and have fb's token: Usually inside the function's listener of FBSDKAccessTokenDidChange Notification, you sign in the user with Firebase with Facebook's token.

      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. Since the user already have an account with this email address which he's now trying to sign in with Facebook, so an error will occurs: as you see in step 4, now you need to sign in the user before you link is account to 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)
                    }
        
                })
        }
        

      2. This way you will have the following result in Firebase console:

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

      Link auth provider credentials to a user account

      To link auth provider credentials to an existing user account:

      1. Sign in the user using any authentication provider or method.

      1. Complete the sign-in flow for the new authentication provider up to, but not including, calling one of the FIRAuth.signInWith methods. For example, get the user's Google ID token, Facebook access token, or email and password.
      2. Get a FIRAuthCredential for the new authentication provider

      这篇关于如何在Firebase中管理用户的不同身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆