如何在 Firebase 中将 emailAndPasswordAuth 与 PhoneAuth 合并?
Posted
技术标签:
【中文标题】如何在 Firebase 中将 emailAndPasswordAuth 与 PhoneAuth 合并?【英文标题】:How to merge emailAndPasswordAuth with PhoneAuth in Firebase? 【发布时间】:2018-11-26 11:54:33 【问题描述】:我正在尝试首先使用Email and Password
登录用户,然后在它之后,我也想要user's Phone Number
。所以我所做的我首先在一个活动(自定义登录)上使用他的EmailAndPasswordAuth
为用户签名,然后,我在下一个活动中通过他的电话号码登录用户。但是由于它变成了同一部手机上的两个帐户,我想将这些 google 和手机凭据合并到一个帐户中。
然后我尝试关注https://firebase.google.com/docs/auth/android/account-linking,但它给了我例外。
com.google.firebase.FirebaseException:用户已链接到给定的提供者。
PhoneAuthActivity.java
String email = intent.getStringExtra("email");
String password = intent.getStringExtra("pass");
Toast.makeText(this, "Email" + email + "Password" + password, Toast.LENGTH_SHORT).show();// this is working
emailCredential = EmailAuthProvider.getCredential(email, password);
mPhoneNumberField = findViewById(R.id.field_phone_number);
mVerificationField = findViewById(R.id.field_verification_code);
mStartButton = findViewById(R.id.button_start_verification);
mVerifyButton = findViewById(R.id.button_verify_phone);
mResendButton = findViewById(R.id.button_resend);
mStartButton.setOnClickListener(this);
mVerifyButton.setOnClickListener(this);
mResendButton.setOnClickListener(this);
mAuth = FirebaseAuth.getInstance();
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks()
@Override
public void onVerificationCompleted(PhoneAuthCredential credential)
Log.d(TAG, "onVerificationCompleted:" + credential);
signInWithPhoneAuthCredential(credential);
@Override
public void onVerificationFailed(FirebaseException e)
Log.w(TAG, "onVerificationFailed", e);
if (e instanceof FirebaseAuthInvalidCredentialsException)
mPhoneNumberField.setError("Invalid phone number.");
else if (e instanceof FirebaseTooManyRequestsException)
Snackbar.make(findViewById(android.R.id.content), "Quota exceeded.",
Snackbar.LENGTH_SHORT).show();
@Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token)
Log.d(TAG, "onCodeSent:" + verificationId);
mVerificationId = verificationId;
mResendToken = token;
;
private void signInWithPhoneAuthCredential(PhoneAuthCredential credential)
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>()
@Override
public void onComplete(@NonNull Task<AuthResult> task)
if (task.isSuccessful())
Log.d(TAG, "signInWithCredential:success");
FirebaseUser user = task.getResult().getUser();
linkCredential(emailCredential);
startActivity(new Intent(PhoneActivity.this, MainActivity.class));
finish();
else
Log.w(TAG, "signInWithCredential:failure", task.getException());
if (task.getException() instanceof FirebaseAuthInvalidCredentialsException)
mVerificationField.setError("Invalid code.");
);
private void startPhoneNumberVerification(String phoneNumber)
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
mCallbacks); // OnVerificationStateChangedCallbacks
private void verifyPhoneNumberWithCode(String verificationId, String code)
PhoneAuthCredential credential = PhoneAuthProvider.getCredential(verificationId, code);
signInWithPhoneAuthCredential(credential);
private void resendVerificationCode(String phoneNumber,
PhoneAuthProvider.ForceResendingToken token)
PhoneAuthProvider.getInstance().verifyPhoneNumber(
phoneNumber, // Phone number to verify
60, // Timeout duration
TimeUnit.SECONDS, // Unit of timeout
this, // Activity (for callback binding)
mCallbacks, // OnVerificationStateChangedCallbacks
token); // ForceResendingToken from callbacks
private boolean validatePhoneNumber()
String phoneNumber = mPhoneNumberField.getText().toString();
if (TextUtils.isEmpty(phoneNumber))
mPhoneNumberField.setError("Invalid phone number.");
return false;
return true;
@Override
public void onStart()
super.onStart();
FirebaseUser currentUser = mAuth.getCurrentUser();
if (currentUser != null)
@Override
public void onClick(View view)
switch (view.getId())
case R.id.button_start_verification:
if (!validatePhoneNumber())
return;
startPhoneNumberVerification(mPhoneNumberField.getText().toString());
break;
case R.id.button_verify_phone:
String code = mVerificationField.getText().toString();
if (TextUtils.isEmpty(code))
mVerificationField.setError("Cannot be empty.");
return;
verifyPhoneNumberWithCode(mVerificationId, code);
break;
case R.id.button_resend:
resendVerificationCode(mPhoneNumberField.getText().toString(), mResendToken);
break;
public void linkCredential(AuthCredential credential)
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>()
@Override
public void onComplete(@NonNull Task<AuthResult> task)
if (task.isSuccessful())
Log.d(TAG, "linkWithCredential:success");
FirebaseUser user = task.getResult().getUser();
Toast.makeText(PhoneActivity.this, "Merged", Toast.LENGTH_SHORT).show();
else
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(PhoneActivity.this, "Failed to merge" + task.getException().toString(), Toast.LENGTH_SHORT).show();
);
正如评论所说,我使用了我自己的自定义 phoneAuth,而不是使用 FirebaseUI 提供的那个,请帮助我将这两个帐户合并为一个。
在 firebase 控制台中,它正在形成两个帐户。
【问题讨论】:
您没有正确初始化电话凭证。您需要构建自己的手机身份验证流程,因为 FirebaseUI 不处理链接,然后在使用 FirebaseUI 注册的用户上进行 linkWithCredential。 嘿,我已经构建了自己的自定义 PhoneAuth,但同样的问题仍然存在。 :( 【参考方案1】:我同意answer of @kruti ,多次验证用户是错误的方式。
-
首先将电子邮件和密码存储在一个变量中
-
用电话号码登录用户,这将为该用户生成一个用户ID
然后您可以将电子邮件和密码与此 Firebase 帐户相关联(前提是您的数据结构良好)
通过手机验证获取生成的id
var myid = firebase.auth().currentuser.uid
现在将信息与帐户关联
firebase.database().ref('Users/' + myid).push(
Email : useremail
Password : userpassword
)
【讨论】:
最好使用指向另一个答案的链接,而不是声明“上述答案”。对我来说,另一个答案目前低于这个...... 如果我使用 google 或 facebook 登录用户怎么办,那么我也需要电话号码,但是 googleIdToken 在用户登录之前不会生成。不是吗? 冥想这在这种情况下可能会有所帮助firebase.google.com/docs/auth/android/account-linking meditat 它将保留 id 直到您在手机验证后保存用户数据【参考方案2】:我猜你做错了。
文档中提到的流程:
完成新身份验证提供程序的登录流程,直至(但不包括)调用 FirebaseAuth.signInWith 方法之一。例如,获取用户的 Google ID 令牌、Facebook 访问令牌或电子邮件和密码。
从documentation of linking auth provider steps 中引用,提到你不应该调用任何FirebaseAuth.signInWith
方法,而是你需要:-
-
获取新身份验证提供程序的 AuthCredential
将AuthCredential
对象传递给登录用户的linkWithCredential
方法,如下所示:
mAuth.getCurrentUser().linkWithCredential(credential)
由于用户已经与一个身份验证提供商签署,我们不需要再次签署他。我们只需要链接这两个提供商,这样他就可以使用其中一个提供商再次登录。
正如您的代码流程所示,在验证电话号码后,您正在使用PhoneAuthCredential
再次登录用户,然后您尝试链接emailCredential
;当前登录的用户已经链接到它,因此出现错误。
这应该是mCallbacks
的代码:
mCallbacks = new PhoneAuthProvider.OnVerificationStateChangedCallbacks()
@Override
public void onVerificationCompleted(PhoneAuthCredential credential)
Log.d(TAG, "onVerificationCompleted:" + credential);
linkCredential(credential);
@Override
public void onVerificationFailed(FirebaseException e)
Log.w(TAG, "onVerificationFailed", e);
if (e instanceof FirebaseAuthInvalidCredentialsException)
mPhoneNumberField.setError("Invalid phone number.");
else if (e instanceof FirebaseTooManyRequestsException)
Snackbar.make(findViewById(android.R.id.content), "Quota exceeded.",
Snackbar.LENGTH_SHORT).show();
@Override
public void onCodeSent(String verificationId,
PhoneAuthProvider.ForceResendingToken token)
Log.d(TAG, "onCodeSent:" + verificationId);
mVerificationId = verificationId;
mResendToken = token;
;
这是linkCredentials
方法。
public void linkCredential(AuthCredential credential)
mAuth.getCurrentUser().linkWithCredential(credential)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>()
@Override
public void onComplete(@NonNull Task<AuthResult> task)
if (task.isSuccessful())
Log.d(TAG, "linkWithCredential:success");
FirebaseUser user = task.getResult().getUser();
Toast.makeText(PhoneActivity.this, "Merged", Toast.LENGTH_SHORT).show();
moveToHome();
else
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(PhoneActivity.this, "Failed to merge" + task.getException().toString(), Toast.LENGTH_SHORT).show();
);
【讨论】:
我已经提到了您需要替换的代码。 你能说出它与预期的不正确吗? 您能解释一下原因吗?还是你这么说是为了可读性? 让我们continue this discussion in chat. 在 firebase 控制台中仍然显示两个帐户 ID?以上是关于如何在 Firebase 中将 emailAndPasswordAuth 与 PhoneAuth 合并?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Flutter 移动应用中将 Azure AD 用户登录到 Firebase?
如何在 Firebase 中将多个 Recyclerview 设置为单个适配器(多视图类型)?
如何在android中将日期转换为firebase时间戳格式