React项目Firebase OTP认证reCaptcha无效错误求助
解决Firebase手机号OTP认证的
auth/invalid-app-credential错误 问题根源分析
你遇到的auth/invalid-app-credential错误,主要由以下原因导致:
- 每次点击发送OTP时,通过innerHTML重置recaptcha容器,导致之前初始化的
RecaptchaVerifier关联DOM元素被销毁,生成的验证令牌直接失效。 - 未等待RecaptchaVerifier完成初始化与验证流程,就直接调用
signInWithPhoneNumber,此时recaptcha尚未生成有效令牌。 - 隐形recaptcha(
size:'invisible')需要正确触发验证流程,直接调用登录方法会跳过核心验证步骤。
修复步骤
- 避免重复创建recaptcha容器:仅在组件挂载时初始化一次容器,不要每次点击按钮都重置。
- 复用RecaptchaVerifier实例:将verifier实例存入useRef,避免重复初始化。
- 确保recaptcha完成验证:调用verifier的
verify()方法手动触发隐形recaptcha验证,确保令牌有效后再发送OTP请求。 - 检查Firebase配置:确认Firebase控制台已添加当前项目域名到「授权域名」列表,否则recaptcha令牌会被判定无效。
修改后的完整代码
import React, { useState, useRef, useEffect } from "react"; import firebase from "../firebase"; const Auth = () => { const [phoneNumber, setPhoneNumber] = useState(''); const [verificationID, setVerificationID] = useState(''); const recaptchaRef = useRef(null); const verifierRef = useRef(null); // 存储verifier实例,避免重复初始化 useEffect(() => { // 组件挂载时一次性初始化recaptcha容器与verifier if (recaptchaRef.current && !verifierRef.current) { const container = document.createElement('div'); container.id = 'recaptcha-container'; recaptchaRef.current.appendChild(container); verifierRef.current = new firebase.auth.RecaptchaVerifier('recaptcha-container', { size: 'invisible', callback: () => console.log('Recaptcha验证成功'), 'expired-callback': () => { // 验证过期时重置verifier,下次点击重新初始化 verifierRef.current = null; } }); } }, []); const handleSendOtp = async () => { if (!verifierRef.current) { console.log('Recaptcha未初始化完成'); return; } try { // 手动触发隐形recaptcha验证 await verifierRef.current.verify(); // 验证通过后发送OTP const confirmationResult = await firebase.auth().signInWithPhoneNumber(phoneNumber, verifierRef.current); setVerificationID(confirmationResult.verificationId); console.log('OTP发送成功'); } catch (error) { console.log('Error sending OTP:', error); // 验证失败时重置verifier与容器 verifierRef.current = null; if (recaptchaRef.current) recaptchaRef.current.innerHTML = ''; } }; return( <div> <h1>Phone OTP Authentication</h1> <div ref={recaptchaRef}></div> <input type="tel" placeholder="+91 9999999999" value={phoneNumber} onChange={e => setPhoneNumber(e.target.value)} /> <button onClick={handleSendOtp}>Send OTP</button> </div> ); }; export default Auth;
额外注意事项
- 确认
../firebase配置文件中的apiKey、authDomain等参数完全正确,且authDomain对应的域名已添加到Firebase控制台「Authentication」→「设置」→「授权域名」列表。 - 本地测试时,需将
localhost加入授权域名列表。 - 可给发送按钮添加禁用状态,防止频繁点击触发重复请求。
内容的提问来源于stack exchange,提问作者Hardik Chawhan
相关产品推荐
相关产品推荐

