Firebase电话认证非测试号码出现无效验证器错误的原因与解决
Firebase手机号验证:非测试号码触发reCAPTCHA无效错误的排查与解决
问题场景
- 测试号码(Sim1):已添加至Firebase控制台「Phone Authentication」测试号码列表,验证流程正常,输入号码后收到OTP发送提示,使用控制台预定义OTP可成功创建用户。
- 真实号码(Sim2):未添加为测试号码,输入号码后reCAPTCHA组件正常显示,完成验证后未收到OTP,触发错误:
The phone verification request contains an invalid application verifier. The reCAPTCHA token response is either invalid or expired.
代码实现
Firebase配置
import firebase from 'firebase'; import "firebase/auth"; // For Firebase JS SDK v7.20.0 and later, measurementId is optional const firebaseConfig = { apiKey: "xxxxxxxxxxxxx", authDomain: "xxxxxxxxxx", projectId: "xxxxxxxxx", storageBucket: "xxxxxxxxxx", messagingSenderId: "xxxxxxxxxxxx", appId: "xxxxxxxxxxxxxx", measurementId: "xxxxxxxxxxxxx" }; // Initialize Firebase firebase.initializeApp(firebaseConfig); const projectStorage = firebase.storage(); const projectFirestore = firebase.firestore(); const timestamp = firebase.firestore.FieldValue.serverTimestamp(); const auth = firebase.auth(); const provider = new firebase.auth.GoogleAuthProvider(); const increment = firebase.firestore.FieldValue.increment(1); export { projectStorage, projectFirestore, timestamp, auth, provider, increment, firebase };
React验证组件
import React, { useState } from "react"; import firebase from "firebase"; // Import the Firebase config const PhoneAuth = () => { const [phoneNumber, setPhoneNumber] = useState(""); const [otp, setOtp] = useState(""); const [verificationId, setVerificationId] = useState(""); // Initialize reCAPTCHA const initializeRecaptcha = () => { window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier("recaptcha-container", { size: "normal", callback: (response) => { console.log("reCAPTCHA solved:", response); }, "expired-callback": () => { console.error("reCAPTCHA expired. Please try again."); }, }); window.recaptchaVerifier.render().then((widgetId) => { console.log("reCAPTCHA rendered with widget ID:", widgetId); }); }; // Send OTP const handleSendCode = () => { initializeRecaptcha(); // Reinitialize reCAPTCHA every time const appVerifier = window.recaptchaVerifier; firebase .auth() .signInWithPhoneNumber(phoneNumber, appVerifier) .then((confirmationResult) => { setVerificationId(confirmationResult.verificationId); alert("OTP sent!"); }) .catch((error) => { console.error("Error during phone auth:", error); alert(error.message); }); }; // Verify OTP const handleVerifyCode = () => { const credential = firebase.auth.PhoneAuthProvider.credential(verificationId, otp); firebase .auth() .signInWithCredential(credential) .then(() => { alert("Phone number verified successfully!"); }) .catch((error) => { console.error("Error verifying OTP:", error); alert(error.message); }); }; return ( <div className="phone-auth"> <h2>Phone Authentication</h2> <div id="recaptcha-container"></div> <input type="text" placeholder="Enter phone number (+1234567890)" value={phoneNumber} onChange={(e) => setPhoneNumber(e.target.value)} /> <button onClick={handleSendCode}>Send OTP</button> <input type="text" placeholder="Enter OTP" value={otp} onChange={(e) => setOtp(e.target.value)} /> <button onClick={handleVerifyCode}>Verify OTP</button> </div> ); }; export default PhoneAuth;
已尝试的排查步骤
- 确认Firebase控制台中Phone Authentication功能已启用;
- 已将应用域名(如开发环境的localhost)添加至授权域名列表;
- 验证reCAPTCHA组件对测试号码可正常工作,但对非测试号码失效。
核心问题
为何非测试号码会触发该无效验证器错误?如何解决此问题?
解决方案
1. 修复reCAPTCHA重复初始化问题
当前代码每次点击「Send OTP」都会重新创建reCAPTCHA实例,覆盖旧实例后,用户完成的旧实例验证token会失效。修改方式:
- 组件挂载时仅初始化一次reCAPTCHA;
- 需要重置验证时调用
reset()方法,而非重新创建实例。
修改后的关键代码:
// 组件挂载时初始化reCAPTCHA React.useEffect(() => { initializeRecaptcha(); }, []); const initializeRecaptcha = () => { // 避免重复创建实例 if (!window.recaptchaVerifier) { window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier("recaptcha-container", { size: "normal", callback: (response) => { console.log("reCAPTCHA solved:", response); }, "expired-callback": () => { console.error("reCAPTCHA expired. Please try again."); alert("验证码已过期,请重新验证"); window.recaptchaVerifier.reset(); }, }); window.recaptchaVerifier.render().then((widgetId) => { console.log("reCAPTCHA rendered with widget ID:", widgetId); }); } }; // Send OTP const handleSendCode = () => { // 重置reCAPTCHA,确保每次请求使用新的验证会话 window.recaptchaVerifier.reset(); // 手机号格式校验 if (!phoneNumber.startsWith('+') || phoneNumber.length < 10) { alert("请输入正确的手机号格式,需包含国家代码(如+8613xxxxxxxxx)"); return; } const appVerifier = window.recaptchaVerifier; firebase .auth() .signInWithPhoneNumber(phoneNumber, appVerifier) .then((confirmationResult) => { setVerificationId(confirmationResult.verificationId); alert("OTP sent!"); }) .catch((error) => { console.error("Error during phone auth:", error); alert(error.message); }); };
2. 确保手机号格式合规
Firebase要求手机号必须包含正确的国家代码(如+86、+1),且无空格、特殊字符。添加前置校验可避免因格式错误导致的隐性验证失败。
3. 检查reCAPTCHA配置一致性
- 确认Firebase控制台「Phone Authentication」的reCAPTCHA类型设置正确(开发环境可选v2,生产环境推荐invisible类型);
- 若使用自定义域名,确保域名已同时添加到Firebase授权域名列表和Google reCAPTCHA控制台的允许域名列表。
内容的提问来源于stack exchange,提问作者Minenhle Solson Cele
相关产品推荐
相关产品推荐

