Flutter不使用Firebase Auth如何自动发送短信/邮箱验证码
Flutter+PHP自建栈实现短信/邮箱验证码自动发送方案
你之前通过
sms:URI scheme调起系统短信应用的方案,本质是引导用户手动发送短信,从设计层面就无法实现验证码自动下发的需求,且存在严重安全隐患——验证码的生成、发送、校验核心逻辑必须全部收敛到后端,端上仅承担参数传递和交互反馈的职责,绝对不能在端上生成验证码、触发发送动作,否则极易被恶意刷取短信额度,也完全无法保障校验逻辑安全。
核心实现逻辑
整套方案完全不依赖Firebase,适配现有PHP+MySQL技术栈,不需要调整原有架构,流程如下:
- 端上收集用户输入的手机号/邮箱地址,做基础格式校验后,请求后端发送验证码接口
- 后端完成频率校验、生成随机验证码、持久化存储到MySQL后,调用对应短信/邮件服务通道下发验证码
- 后端将发送结果返回给端上,端上根据结果做倒计时、提示用户查收
- 用户输入验证码后,端上回传验证码给后端,后端完成校验后返回业务结果
短信验证码实现步骤
- 服务通道准备
不需要自行对接运营商网关,直接选择正规第三方短信服务即可,国内可选阿里云短信、腾讯云短信,海外可选Twilio、Plivo,在对应服务平台完成企业/个人认证,申请短信签名、验证码模板,拿到接口调用的API密钥和模板ID。 - 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'=>'发送成功']); - 验证码校验接口逻辑:接收端上传入的手机号和用户输入的验证码,查询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
相关产品推荐
相关产品推荐

