请帮助我在以下情况下找到正确的解决方案。
我正在使用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描述了如何链接身份验证提供程序的方式,但是用户应该使用一种方法登录,并且只有在此之后才能链接帐户。
如果您已拥有oauth凭据,则使用linkWithCredential
方法。如果用户是在一台带有电子邮件的设备上创建的,那么如果他决定再次使用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)
不确定这是不是一个好选择?
感谢您的回复。
答案 0 :(得分: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
}
}
4.现在在另一台设备上,用户决定使用Facebook(不同的提供商)登录
用Facebook登录用户并拥有fb的令牌后:通常在函数的FBSDKAccessTokenDidChange
通知的监听器内,您使用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控制台中获得以下结果:
Firebase文档: https://firebase.google.com/docs/auth/ios/account-linking
将身份验证提供程序凭据链接到用户帐户
将身份验证提供程序凭据链接到现有用户帐户:
<强> 1。使用任何身份验证提供程序或方法登录用户。
- 完成新身份验证提供程序的登录流程,但不包括调用其中一个FIRAuth.signInWith方法。 例如,获取用户的Google ID令牌,Facebook访问令牌或 电子邮件和密码。
- 获取新身份验证提供程序的FIRAuthCredential
醇>