Android应用Firebase邮箱认证与手机号二次验证集成方法问询
我刚好做过类似的集成,给你梳理一套完整的可落地方案,一步步来就很清晰:
集成Firebase邮箱密码+手机号双重认证的完整方案
一、前期准备
- 确保你的Firebase项目已经启用了邮箱/密码认证和手机号认证(在Firebase控制台的Authentication>Sign-in method里开启)
- 提前规划用户数据存储:把用户的手机号、2FA启用状态(比如
is2FAEnabled)绑定到已有邮箱账号,建议存在Firestore的用户专属文档里,或者Firebase Auth的用户自定义字段中
二、核心登录流程设计
用户的完整登录路径应该是:
- 用户输入邮箱+密码,完成Firebase邮箱密码基础登录
- 登录成功后,检查该用户是否开启了2FA
- 未开启2FA:直接进入应用主界面
- 已开启2FA:触发手机号验证码验证流程,验证通过后方可进入主界面
三、具体代码实现步骤
1. 保留原有邮箱密码登录逻辑
// 邮箱密码登录核心代码 val emailInput = binding.etEmail.text.toString() val passwordInput = binding.etPassword.text.toString() FirebaseAuth.getInstance().signInWithEmailAndPassword(emailInput, passwordInput) .addOnCompleteListener { task -> if (task.isSuccessful) { val currentUser = FirebaseAuth.getInstance().currentUser // 登录成功后立即检查2FA状态 checkUser2FAStatus(currentUser) } else { Toast.makeText(this, "登录失败:${task.exception?.message}", Toast.LENGTH_SHORT).show() } }
2. 检查用户2FA启用状态
这里以Firestore存储用户数据为例:
private fun checkUser2FAStatus(user: FirebaseUser?) { user ?: return val db = FirebaseFirestore.getInstance() db.collection("users").document(user.uid) .get() .addOnSuccessListener { doc -> val is2FAEnabled = doc.getBoolean("is2FAEnabled") ?: false val boundPhone = doc.getString("boundPhone") ?: "" if (is2FAEnabled && boundPhone.isNotEmpty()) { // 启动手机号验证码验证流程 triggerPhoneVerification(boundPhone) } else { // 直接进入主界面 startActivity(Intent(this, MainActivity::class.java)) finish() } } }
3. 手机号验证码验证流程(关键集成点)
这里不需要用手机号登录,而是用Firebase的PhoneAuthProvider完成验证码的发送与验证,核心是验证用户对绑定手机号的所有权:
private lateinit var verificationId: String private lateinit var resendToken: PhoneAuthProvider.ForceResendingToken // 发送验证码到用户绑定的手机号 private fun triggerPhoneVerification(phoneNumber: String) { val options = PhoneAuthOptions.newBuilder(FirebaseAuth.getInstance()) .setPhoneNumber(phoneNumber) // 必须带国家码,比如+86138xxxxxxx .setTimeout(60L, TimeUnit.SECONDS) // 验证码有效期 .setActivity(this) // 当前上下文Activity .setCallbacks(object : PhoneAuthProvider.OnVerificationStateChangedCallbacks() { override fun onVerificationCompleted(credential: PhoneAuthCredential) { // 自动验证成功(比如可信设备),直接完成验证 verifyPhoneCredential(credential) } override fun onVerificationFailed(e: FirebaseException) { Toast.makeText(this@LoginActivity, "验证码发送失败:${e.message}", Toast.LENGTH_SHORT).show() } override fun onCodeSent(id: String, token: PhoneAuthProvider.ForceResendingToken) { // 验证码发送成功,保存凭证用于后续验证 verificationId = id resendToken = token // 弹出验证码输入框或跳转到验证页面 showCodeInputDialog() } }) .build() PhoneAuthProvider.verifyPhoneNumber(options) } // 验证验证码凭证 private fun verifyPhoneCredential(credential: PhoneAuthCredential) { FirebaseAuth.getInstance().signInWithCredential(credential) .addOnCompleteListener { task -> if (task.isSuccessful) { // 手机号验证通过,进入主界面 startActivity(Intent(this, MainActivity::class.java)) finish() } else { Toast.makeText(this, "验证码错误,请重新输入", Toast.LENGTH_SHORT).show() } } } // 用户手动输入验证码后的验证逻辑 private fun verifyUserInputCode(inputCode: String) { val credential = PhoneAuthProvider.getCredential(verificationId, inputCode) verifyPhoneCredential(credential) }
4. 用户启用2FA的设置逻辑(补充)
在应用设置页面,需要让用户先绑定手机号并验证,再开启2FA:
// 用户在设置页开启2FA的逻辑 fun enableUser2FA(phoneNumber: String) { // 先验证手机号有效性 triggerPhoneVerification(phoneNumber) // 验证成功后更新用户的2FA状态 val currentUser = FirebaseAuth.getInstance().currentUser ?: return FirebaseFirestore.getInstance().collection("users").document(currentUser.uid) .update(mapOf( "is2FAEnabled" to true, "boundPhone" to phoneNumber )) .addOnSuccessListener { Toast.makeText(this, "双重认证已成功启用", Toast.LENGTH_SHORT).show() } }
四、关键注意事项
- 手机号格式必须规范:必须包含国家码(如
+86),否则Firebase会拒绝发送验证码 - 要提供验证码重发功能:利用之前保存的
resendToken调用PhoneAuthProvider.verifyPhoneNumber时传入即可 - 可选优化:验证成功后可标记当前设备为可信设备,下次登录无需验证(可在用户文档中存储设备ID列表)
- 安全规则:Firestore的用户文档要设置严格的安全规则,确保只有用户本人能读取和修改自己的2FA状态
内容的提问来源于stack exchange,提问作者Hary
相关产品推荐
相关产品推荐

