android - 如何在 Firebase 中将电话与电子邮件和密码身份验证相关联?
问题描述
我正在尝试创建一个应用程序,用户可以使用用户名和密码进行注册,然后输入电话号码,接收 OTP 代码,并填写注册表单。但有一个问题。如果您这样做,Firebase 会创建两个不同的用户。如何组合(加入)它们以使其显示为单个帐户?
输入电话号码的活动:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_signup2)
init()
var phoneNumber: String
mBackBtn.setOnClickListener {
}
mNextBtn.setOnClickListener {
phoneNumber = "+" + mCountyCode!!.selectedCountryCode + mPhoneNumberEd.text.toString()
Toast.makeText(this, phoneNumber, Toast.LENGTH_LONG).show()
sendVerificationCode(phoneNumber)
}
}
private fun sendVerificationCode(phone: String) {
var phoneShadow = phone
Log.d("MyTag", phoneShadow)
val options = PhoneAuthOptions.newBuilder()
.setPhoneNumber(phoneShadow)
.setTimeout(60L, TimeUnit.SECONDS)
.setActivity(this)
.setCallbacks(callbacks)
.build()
PhoneAuthProvider.verifyPhoneNumber(options)
}
private fun init() {
callbacks = object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() {
override fun onVerificationCompleted(credential: PhoneAuthCredential) {
Log.d(TAG, "onVerificationCompleted:$credential")
val intent = Intent(applicationContext, Signup3::class.java)
startActivity(intent)
}
override fun onVerificationFailed(e: FirebaseException) {
Log.d(TAG, "onVerificationFailed", e)
Toast.makeText(applicationContext, "Failed", Toast.LENGTH_LONG).show()
}
override fun onCodeSent(verificationId: String, token: PhoneAuthProvider.ForceResendingToken) {
Log.d("MyTag","onCodeSent:$verificationId")
var storedVerificationId: String = verificationId
var resendToken: PhoneAuthProvider.ForceResendingToken = token
val intent = Intent(applicationContext, Signup3::class.java)
intent.putExtra("storedVerificationId", storedVerificationId)
startActivity(intent)
}
}
mNextBtn = findViewById(R.id.signup2_next_btn)
mBackBtn = findViewById(R.id.signup2_back_btn)
mPhoneNumberEd = findViewById(R.id.signup2_phone_number_ed)
mCountyCode = findViewById(R.id.signup2_county_code)
mAuth = FirebaseAuth.getInstance()
}
输入手机收到的代码的活动:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_signup3)
init()
var storedVerificationId = intent.getStringExtra("storedVerificationId").toString()
mConfirmBtn.setOnClickListener {
var code = mPinView.text.toString().trim()
if (code.isEmpty()) {
Toast.makeText(this, "Ты ввёл?", Toast.LENGTH_LONG).show()
} else {
var credential : PhoneAuthCredential = PhoneAuthProvider.getCredential(storedVerificationId!!, code)
signInWithPhoneAuthCredential(credential)
}
}
}
private fun init() {
mConfirmBtn = findViewById(R.id.signup3_confirm_btn)
mPinView = findViewById(R.id.signup3_pin_view)
mAuth = FirebaseAuth.getInstance()
}
private fun signInWithPhoneAuthCredential(credential: PhoneAuthCredential) {
mAuth.signInWithCredential(credential)
.addOnCompleteListener(this) {
if (it.isSuccessful) {
var intent = Intent(this, PhoneConfirmedSignup::class.java)
startActivity(intent)
finish()
} else {
if (it.exception is FirebaseAuthInvalidCredentialsException) {
Toast.makeText(this, "Invalid OTP", Toast.LENGTH_SHORT).show()
}
}
}
}
解决方案
如果您这样做,Firebase 会创建两个不同的用户。
这是预期的行为,因为您使用两种不同类型的身份验证。
如何将它们组合起来,使其显示为一个帐户?
如果您只想拥有一个,那么您应该将它们链接到一个帐户中。根据有关帐户链接的官方文档,首先,您需要获取现有凭据:
val authCredential = EmailAuthProvider.getCredential(email, password)
对于 Java 用户:
AuthCredential authCredential = EmailAuthProvider.getCredential(email, password);
然后只需使用FirebaseUser#linkWithCredential(AuthCredential credential)方法,如下面的代码行所示:
val auth = FirebaseAuth.getInstance()
auth.currentUser!!.linkWithCredential(credential).addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
Log.d(TAG, "linkWithCredential:success")
val user = task.result!!.user
updateUI(user)
} else {
Log.w(TAG, "linkWithCredential:failure", task.exception)
Toast.makeText(this, "Authentication failed.", Toast.LENGTH_SHORT).show()
updateUI(null)
}
}
对于 Java 用户:
FirebaseAuth auth = FirebaseAuth.getInstance();
auth.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();
updateUI(user);
} else {
Log.w(TAG, "linkWithCredential:failure", task.getException());
Toast.makeText(AnonymousAuthActivity.this, "Authentication failed.", Toast.LENGTH_SHORT).show();
updateUI(null);
}
}
});
推荐阅读
- time-complexity - 该语句将执行多少次?
- swift - 尝试使用字符串比较过滤数据时,SwiftUI 无法编译
- laravel-5.7 - 无法使用 Dusk 运行 Laravel 浏览器测试
- java - 来自 Spring Web 服务的响应未格式化
- sql - Postgresql 更新查询挂起 - 但如果我添加 1 分钟暂停将完成
- javascript - 如何在 .jsx 文件中将绝对路径更改为相对路径。(Photoshop 扩展脚本)?
- c# - 合并 2 条具有相同架构的 xml 记录
- php - 使用 bootstrap-table.js 显示 html 时出现问题
- c# - 如何用正则表达式计算这个字符串?
- vb.net - 由 SUBST (Windows 10) 创建的驱动器未报告 QueryDosDevice() 的完整路径