如何在Firebase中管理用户的不同身份验证 [英] How to manage users' different authentication in 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
显然我希望这两个账户自动合并。
与任何的这些方式的 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用户登录)
}
-
由于用户已经拥有了一个他正在用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)
}
}}
}
-
这样,您将在Firebase控制台:
醇>
Firebase文档:
https://firebase.google.com/docs/auth/ios/account-linking
连结认证供应商凭证到用户帐户
要将认证提供者凭证关联到现有用户帐户,请执行以下操作:
使用任何身份验证提供程序或方法登录用户。
- 完成登录流程新的身份验证提供程序直到但不包括调用FIRAuth.signInWith方法之一。
例如,获取用户的Google ID令牌,Facebook访问令牌或
电子邮件和密码。
- 获取新身份验证提供程序的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
}
}
- 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")
}
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)
}
})
}
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.
- 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.
- Get a FIRAuthCredential for the new authentication provider
这篇关于如何在Firebase中管理用户的不同身份验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!