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

Flutter不使用Firebase Auth如何自动发送短信/邮箱验证码

Flutter+PHP自建栈实现短信/邮箱验证码自动发送方案

你之前通过sms: URI scheme调起系统短信应用的方案,本质是引导用户手动发送短信,从设计层面就无法实现验证码自动下发的需求,且存在严重安全隐患——验证码的生成、发送、校验核心逻辑必须全部收敛到后端,端上仅承担参数传递和交互反馈的职责,绝对不能在端上生成验证码、触发发送动作,否则极易被恶意刷取短信额度,也完全无法保障校验逻辑安全。


核心实现逻辑

整套方案完全不依赖Firebase,适配现有PHP+MySQL技术栈,不需要调整原有架构,流程如下:

  • 端上收集用户输入的手机号/邮箱地址,做基础格式校验后,请求后端发送验证码接口
  • 后端完成频率校验、生成随机验证码、持久化存储到MySQL后,调用对应短信/邮件服务通道下发验证码
  • 后端将发送结果返回给端上,端上根据结果做倒计时、提示用户查收
  • 用户输入验证码后,端上回传验证码给后端,后端完成校验后返回业务结果

短信验证码实现步骤

  1. 服务通道准备
    不需要自行对接运营商网关,直接选择正规第三方短信服务即可,国内可选阿里云短信、腾讯云短信,海外可选Twilio、Plivo,在对应服务平台完成企业/个人认证,申请短信签名、验证码模板,拿到接口调用的API密钥和模板ID。
  2. PHP后端逻辑
    • 提供POST类型的短信发送接口,接收Flutter端传入的手机号参数
    • 做基础校验:校验手机号格式、查询MySQL中该手机号的最近发送记录,1分钟内有发送记录直接返回"发送过于频繁"的错误
    • 生成6位随机数字验证码,将手机号、验证码哈希值、发送时间、过期时间(默认5分钟)写入MySQL
    • 按照你选用的短信服务商的接口要求,组装请求参数(包含签名、模板ID、验证码参数、手机号),通过PHP的curl发起POST请求调用服务商的下发接口
    • 拿到服务商返回的发送成功结果后,给Flutter端返回成功响应,否则返回对应错误
      核心代码片段参考:
    <?php
    // 接收端上传入的手机号参数
    $phone = $_POST['phone'];
    // 手机号格式校验、发送频率校验逻辑省略
    // 生成6位数字验证码
    $code = str_pad(rand(0,999999),6,'0',STR_PAD_LEFT);
    $expireTime = time() + 300; // 5分钟过期
    // 验证码哈希后入库,禁止明文存储
    $codeHash = password_hash($code, PASSWORD_DEFAULT);
    // 写入MySQL逻辑省略,替换为项目现有数据库操作方法
    // 调用短信服务商接口,参数替换为对应服务商的配置要求
    $postData = [
        'PhoneNumbers' => $phone,
        'SignName' => '你的应用签名',
        'TemplateCode' => '你的验证码模板ID',
        'TemplateParam' => json_encode(['code'=>$code])
    ];
    // curl发起请求逻辑省略,按照服务商文档要求添加鉴权头
    // 返回结果给端上
    echo json_encode(['code'=>0,'msg'=>'发送成功']);
    
  3. 验证码校验接口逻辑:接收端上传入的手机号和用户输入的验证码,查询MySQL中该手机号对应的未过期、未使用的验证码记录,用password_verify比对哈希值,比对通过则标记验证码为已使用,返回校验成功,否则返回校验失败。

邮箱验证码实现步骤

邮箱通道不需要额外采购第三方服务,直接用PHP的PHPMailer类库通过SMTP协议发送即可:

  • 准备一个开通了SMTP服务的邮箱(优先使用企业邮箱,避免被判定为垃圾邮件),拿到SMTP服务器地址、端口、发件账号、SMTP授权码
  • PHP后端提供邮箱发送接口,接收Flutter传入的邮箱地址,做格式校验、频率校验,逻辑和短信接口完全一致
  • 生成6位验证码,哈希后和邮箱、过期时间一同写入MySQL
  • 引入PHPMailer类库,配置SMTP参数,组装邮件正文(写入验证码内容),调用发送方法完成邮件下发
  • 校验逻辑和短信验证码完全一致,比对通过即可走后续业务流程。

Flutter端对接逻辑

完全不需要调用系统短信/邮件应用,只需要做普通网络请求即可,核心代码参考:

// 引入项目中使用的网络请求库,比如dio
Future<void> sendSmsCode(String phone) async {
  // 手机号格式校验逻辑省略
  try {
    // 展示加载态
    showLoading();
    final resp = await dio.post('/api/sendSmsCode', data: {'phone': phone});
    dismissLoading();
    if(resp.data['code'] == 0) {
      // 发送成功,启动60秒倒计时,提示用户查收
      startCountdown();
      showToast('验证码已发送,请注意查收');
    } else {
      showToast(resp.data['msg']);
    }
  } catch(e) {
    dismissLoading();
    showToast('发送失败,请稍后重试');
  }
}

如果需要实现收到验证码后自动填充的效果,可以集成sms_autofill插件监听系统短信广播,提取短信中的验证码自动填入输入框,不需要用户手动输入。


必加安全规则

  • 所有短信、邮件服务的API密钥、SMTP授权码全部存在PHP后端配置文件中,绝对不要打包到Flutter端
  • 必须加发送频率限制:同个账号1分钟内限发1次,1小时内最多发5次,24小时最多发10次,避免被恶意刷量产生高额资费
  • 验证码必须设置5分钟过期时间,校验通过后立刻标记为已使用,禁止重复校验
  • 发送接口前置加图形验证码、滑块验证等人机校验逻辑,拦截机器批量请求
  • 数据库中存储的验证码必须做哈希处理,不要明文存储,避免拖库后验证码泄露

内容的提问来源于stack exchange,提问作者ThomasF

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 09:51:46