Итак, это решение, с которым я всегда работал, и оно упоминается в самой документации Firebase
. Прежде всего, вам необходимо понять концепцию связывания Multiple Auth Providers
. Я стараюсь быть максимально продуманным, так как многие из вас сталкиваются с этой проблемой. Firebase
принадлежит Google
, и каждый раз, когда вы входите с помощью Google
, он автоматически переопределяет другие методы входа, такие как Apple Sign In
, Facebook
, Google
.
Итак, для решения этой проблемы используйте кнопку Google Sign In
. Я держу свой ответ в общих чертах c, даже разработчики Javascript
могут следовать этому, как я делал то же самое в JS
.
Вы должны получить email
от Google
и каждого провайдера, например FB, Apple
et c. Затем вы должны использовать этот метод: fetchSignInMethods
.
func fetchSignInMethods(provider: String, email: String) {
Auth.auth().fetchSignInMethods(forEmail: email) { (providers, error) in
if let error = error {
print(error)
return
}
let matched = providers?.filter{ $0 == provider }.count //Here I check if the provider I sent example `Facebook` and the fetched provider are same or not, if it is matched then I can go ahead and login the user directly else I have to show them linking alert as already this email exists with different sign in methods
if providers?.isEmpty || matched == 1 {
var credential: AuthCredential!
switch provider {
case Constants.LoginProviders.Google.rawValue: //google.com
credential = GoogleAuthProvider.credential(withIDToken: idToken,accessToken: token) //idToken and AccessToken are fetched from Google Sign In Button
default: //facebook.com
credential = FacebookAuthProvider.credential(withAccessToken: token) //AccessToken is fetched from Facebook Sign In Button
break
}
self.loginWithCredential(credentail: credential, provider: provider)
} //I am also checking if provider is empty then I can sign them up for Email and Password users using Auth.auth().createUserWithEmailAndPassword
else {
self.displayLinkingAlert(provider: fetchedProviderName)
}
}
}
//This function is used to display the alert when an account needs to be linked
//Provider is the parameter which will be fetched from LoginProviders(Constants.swift)
private func displayLinkingAlert(provider: String) {
MKProgress.hide()
let providerName = getProviderName(provider: provider)
let alertC: UIAlertController = UIAlertController(title: "Link Accounts?", message: "This account is already linked with \(providerName). Do you want to link accounts?", preferredStyle: .alert)
let linkAction: UIAlertAction = UIAlertAction(title: "Link account with \(providerName)", style: .default) { (_) in
self.linkAccounts.toggle() //Toggle linkAccounts to true to link the accounts of user
switch provider {
case Constants.LoginProviders.Google.rawValue:
GIDSignIn.sharedInstance()?.signIn()
break
default: self.facebookLoginWithPermissions(from: LoginViewController())
}
}
let cancelAction: UIAlertAction = UIAlertAction(title: "Cancel", style: .cancel, handler: nil)
let actions: [UIAlertAction] = [linkAction, cancelAction]
actions.forEach{ alertC.addAction($0) }
UIApplication.topViewController()?.present(alertC, animated: true, completion: nil)
} //I also too a private var linkAccounts = false above in the class
//This function is used to get the providerName from the provider
//Ex.:- provider -> google.com, providerName: Google
private func getProviderName(provider: String) -> String
{
var providerName = ""
switch provider
{
case Constants.LoginProviders.Email.rawValue : providerName = "Email"
case Constants.LoginProviders.Facebook.rawValue : providerName = "Facebook"
case Constants.LoginProviders.Google.rawValue : providerName = "Google"
default: break
}
return providerName
}
Теперь, это покажет вам предупреждение о связывании. Ну, это зависит от вас, как вы хотите продолжить. В моих приложениях включены методы входа в систему Google
, Facebook
и Email
, и я показываю пользователям обоих из них случай, если два провайдера выбраны из Firebase
. Например,
Если я уже зарегистрировался с Google
и Facebook
, то, если я попытаюсь зарегистрировать пользователя по электронной почте, он покажет мне две кнопки оповещения Link With Google
и Link With Facebook
. Теперь, если вы хотите, вы можете показать их обоих, или вы можете указать только одно, я могу даже добавить Apple Sign In
здесь, это зависит от выбора каждого.
Теперь, когда появляется предупреждение и вы нажимаете опцию Link With Facebook
, во-первых, toggle
переменная linkAccount
принимает значение true, а затем вызывается метод facebookTap
, который снова fetch
providers
выглядит следующим образом:
private func facebookTap() {
//Get the details and get the email then...
fetchSignInMethods(provider: Constants.LoginProviders.Facebook.rawValue //facebook.com, email: emailFetched) //This will sign in the user using Facebook and as the linkAccount variable is true it will link ther user
}
//A common function used to login the users, by using their credentails
//Parameter credential is of type AuthCredential which is used to
//signInAndRetrieve data of a particular user.
func loginWithCredential(credentail: AuthCredential, provider: String) {
authInstance.signInAndRetrieveData(with: credentail) { [unowned self](authResult, error) in
if let error = error {
print(error)
} else {
if self.linkAccounts {
var loginCredential: AuthCredential!
switch provider {
case Constants.LoginProviders.Google.rawValue:
guard let facebookTokenString = AccessToken.current?.tokenString else { return }
loginCredential = FacebookAuthProvider.credential(withAccessToken: facebookTokenString)
break
default:
loginCredential = GoogleAuthProvider.credential(withIDToken: self.googleIdToken, accessToken: self.googleAccessToken)
break
}
self.linkAccounts(credential: loginCredential)
} else {
self.getFirebaseToken()
}
}
}
}
Теперь я использую это для link
учетных записей:
//This function is used to link the Accounts
//Ex:- Google with Facebook, vice-versa
private func linkAccounts(credential: AuthCredential) {
authInstance.currentUser?.link(with: credential, completion: { (authResult, error) in
if let error = error {
print(error)
return
} else {
self.linkAccounts.toggle() //Toggle Link Account to false as acccounts are already linked
//Navigate user to another page or do your stuff
}
})
}
Теперь это решение, которое я пробовал, и оно работало для меня каждый раз. Он работал для меня в Swift
, Flutter
, Javascript
и будет работать с любым другим языком. Вы можете сделать то же самое с Apple Sign In Button
. В делегате, где вы получите подробную информацию, если пользователь поделился своим адресом электронной почты, вы можете использовать fetchSignInMethods
, и он автоматически отобразится с указанным выше предупреждением. У меня нет возможности связать пользователя, который решил сохранить свою личность в секрете, но я скоро обновлю свой ответ.
Я старался быть максимально подробным, пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы.