如何在 Firebase 中将电话与电子邮件和密码身份验证相关联?

时间:2021-06-22 23:35:20

标签: android firebase kotlin firebase-authentication

我正在尝试创建一个应用程序,用户可以在其中使用用户名和密码进行注册,然后输入电话号码、接收 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()
                }
            }
        }
}

1 个答案:

答案 0 :(得分:1)

<块引用>

如果您这样做,Firebase 会创建两个不同的用户。

这是预期的行为,因为您使用了两种不同类型的身份验证。

<块引用>

如何将它们组合起来,使其显示为一个帐户?

如果您只想拥有一个,那么您应该将它们链接到一个帐户中。根据有关 account linking 的官方文档,首先,您需要获取现有凭据:

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);
        }
    }
});