You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter Web release模式Firebase手机号登录报captcha-check-failed错误

Flutter Web Release模式下Firebase Auth手机号验证报captcha-check-failed错误排查

问题现象

  • 本地debug调试模式下功能运行正常:可正常弹出reCaptcha验证组件,完成验证流程后可正常下发OTP验证码
  • 项目编译为release模式托管到GitHub Pages后:调用signInWithPhoneNumber接口直接返回captcha-check-failed错误,且release环境下完全不会加载显示reCaptcha验证组件
  • 已尝试移除signInWithPhoneNumber的可选参数RecaptchaVerifier测试,问题未解决
  • 错误截图:captcha-check-failed错误截图

当前功能实现代码

Future<void> loginWithPhoneRequestOTPWeb(
  WidgetRef ref,
  GlobalKey<FormState> formKey,
  String phoneNumber,
) async {
  try {
    EasyLoading.show();
    await FirebaseAuth.instance
        .signInWithPhoneNumber(
      phoneNumber,
      RecaptchaVerifier(
        container: 'recaptcha',
        size: RecaptchaVerifierSize.compact,
        theme: RecaptchaVerifierTheme.dark,
        onError: (e) {
          print(e);
          EasyLoading.showError(e.message!);
          return;
        },
        onExpired: () {
          print('Expired');
          EasyLoading.showError('Session Expired');
          return;
        },
        onSuccess: () {
          EasyLoading.dismiss();
          print('Captcha Success');
        },
      ),
    )
        .then((ConfirmationResult result) {
      // update the verificationphone provider
      ref.read(sendOtpProvider(formKey).state).update((_) => true);
      ref.read(confirmationResultProvider(formKey).state).update((_) => result);
      EasyLoading.showSuccess(t!.otpSentSuccessfully);
    });
  } on FirebaseAuthException catch (e) {
    if (e.code == 'invalid-phone-number') {
      print('The provided phone number is not valid.');
      EasyLoading.showError('The provided phone number is not valid.');
    } else if (e.code == 'too-many-requests') {
      print(
          'You have exceeded the number of attempts allowed for this operation.');
      EasyLoading.showError(
          'You have exceeded the number of attempts allowed for this operation.');
    } else {
      print(e.code.toString());
      EasyLoading.showError(e.code.toString());
    }
  } catch (e) {
    print(e.toString());
    EasyLoading.showError(e.toString());
  }
}

排查与修复方案

1. 检查Firebase控制台授权域名配置

GitHub Pages的域名必须加入Firebase Auth的授权域名列表,否则reCaptcha校验会直接失败:

  • 打开Firebase控制台 → 进入对应项目 → Authentication → Settings → Authorized domains
  • 确认你的GitHub Pages域名(格式一般为xxx.github.io,如果使用自定义域名也需要同步添加)已经在列表中,缺失则手动添加

注意:本地debug时默认使用的localhost本身就在Firebase默认授权域名列表里,所以本地不会触发这个问题,这是debug正常release异常的最常见原因

2. 修复release模式下reCaptcha容器渲染问题

代码中指定了container: 'recaptcha',这个参数要求页面中必须存在一个id为recaptcha的DOM元素,Flutter Web release模式下渲染逻辑和debug模式有差异,很可能这个容器元素没有被正确创建/挂载:

  • 打开项目web/index.html文件,在<body>标签内、Flutter挂载节点(一般为<script src="flutter_bootstrap.js" async>之前)手动添加DOM容器:
<div id="recaptcha"></div>
  • 如果不想手动维护容器,可以去掉container参数,让Firebase Auth自动生成和挂载reCaptcha弹窗容器,避免容器不存在导致reCaptcha根本未加载。

3. 检查编译参数与Firebase初始化配置

  • 确认release编译时没有开启过高等级的混淆导致Firebase Auth相关JS调用被截断,可先使用flutter build web --web-renderer html --no-tree-shake-icons命令编译测试,排除canvaskit渲染器和tree-shake带来的兼容问题
  • 确认release环境下Firebase的初始化参数(apiKey、authDomain、projectId等)和debug环境完全一致,不要在release环境下误用其他项目的初始化配置
  • 部署后打开浏览器开发者工具的Console、Network面板,筛选recaptcha、identitytoolkit相关请求,查看是否有资源加载被拦截、跨域报错的情况:GitHub Pages默认的CSP策略如果限制了外部脚本加载,会导致reCaptcha的JS脚本拉取失败,直接触发校验失败。

4. 临时验证方案

可以先把RecaptchaVerifier的size改成RecaptchaVerifierSize.normal,强制显式渲染reCaptcha组件,确认组件本身能正常加载后再调整为compact模式或者隐形模式。


内容的提问来源于stack exchange,提问作者Md. Sabik Alam Rahat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 08:00:58