优先选用 laravel-verification 等轻量验证包或直调厂商 api(如阿里云、腾讯云),验证码须存数据库、走独立服务类,校验需双重判断并立即标记已用,api 场景用自定义中间件 ensuresmsverified 拦截未验证请求。

短信验证该用哪个 Laravel 包
别直接装 laravel-notification-channels/twilio 或一堆封装过头的“短信 SDK”,它们要么只支持单通道,要么把验证码逻辑和通知逻辑混在一起,改个验证码过期时间都得翻源码。真正好用的是 laravel-verification 这类轻量验证包,或者干脆自己用 Illuminate\Support\Facades\Http 直调短信厂商 API——比如阿里云的 /green/text/scan(实名校验)或腾讯云的 /v5/tts/SendSms。
常见错误现象:Class 'App\Notifications\SmsVerification' not found,本质是把通知类当验证服务用了;还有人把 Notification::route('sms', $phone)->notify(new VerifyCode) 当成验证码发送主流程,结果没法查状态、没法限频、没法存记录。
- 优先选厂商官方 SDK(如
alibabacloud/php-sdk),它自带签名、重试、超时控制 - 不要在
AuthController里硬写file_get_contents()调 HTTP,没异常捕获、没连接池、没日志上下文 - 验证码必须走独立服务类(如
SmsCodeService),和登录、注册解耦
验证码怎么存、怎么校验才安全
别用 Cache::put('sms:138xxxxxx', '123456', 300) 这种裸存法。缓存 key 缺少业务前缀易冲突,没绑定用户设备指纹或 IP,容易被撞库;更糟的是用 session() 存验证码——API 场景下 session 默认不生效,TokenMismatchException 会频繁报错。
使用场景:前后端分离项目、APP 接口、小程序后端,都得靠无状态校验。
- 存进数据库表
sms_verifications,字段至少含phone、code、expires_at、used、ip_address - 生成 code 用
Str::random(6, '0123456789'),别用rand(100000, 999999)——可预测、无均匀性保障 - 校验时加双重判断:
where('phone', $phone)->where('code', $code)->where('expires_at', '>', now())->where('used', false) - 校验成功立刻
update(['used' => true]),防止重放
Laravel API 中间件怎么拦住未验证请求
别在每个控制器方法开头写 if (!$request->session()->has('verified')) { abort(403); }。API 没 session,这种写法永远走不到 else;也别用 auth:sanctum 中间件强行套——它管 token,不管短信状态。
正确做法是写一个自定义中间件 EnsureSmsVerified,它只检查当前请求是否带有效且未使用的验证码记录,且与手机号匹配。
- 中间件构造函数里不传任何依赖,避免测试难 mock
- 从
$request->input('phone')和$request->input('code')取值,而不是从 header 或 token 解析——短信验证阶段还没 token - 校验失败返回
response()->json(['message' => 'SMS code invalid or expired'], 422),HTTP 状态码别用 401(那是认证失败) - 这个中间件只挂给
POST /api/login或POST /api/register,别挂到GET /api/user上
阿里云/腾讯云 SDK 报错怎么快速定位
最常卡在签名失败或 region 错误,比如 InvalidAccessKeyId.NotFound 看起来像密钥错了,其实是 region_id 写成 cn-shanghai 但实际开通的是 cn-hangzhou;又比如 SignatureDoesNotMatch 不是密钥泄露,而是时间戳没用 UTC、没对齐服务端时钟。
性能影响:同步调用短信 API 会阻塞请求,一次发码平均耗时 300–800ms,高并发下容易拖垮整个 API 响应。
- 调试时先用厂商控制台「API 调试器」粘贴参数跑通,再比对 SDK 生成的
StringToSign - 在
config/services.php里显式配置'timeout' => 5.0和'connect_timeout' => 3.0,避免无限等待 - 生产环境必须加
try/catch包裹 SDK 调用,捕获ClientException和ServerException,并记录完整 request ID - 高频场景(如测试环境反复注册)建议加本地限流:
RateLimiter::attempt('sms:'.$phone, 5, 60)
真正麻烦的不是发不出去,是发出去了但没人知道它有没有被用户看到——没读取回执、没区分送达/拦截/关机,这些得靠厂商的上行回调或离线日志,Laravel 本身不处理。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











