如何使用PHP/Laravel后端通过API校验Firebase OTP
解决方案:Laravel/PHP 后端对接 Firebase OTP 校验流程
首先明确核心误区:Firebase 不会向客户端、第三方服务暴露其生成的明文OTP内容,你不需要、也无法直接获取Firebase生成的OTP存入自有数据库,自行抓短信内容存OTP的方案既违反Firebase服务规则,也存在验证码泄露、爆破的安全风险。正确的实现逻辑是通过Firebase签发的合法身份凭证完成后端校验,不需要自行存储OTP。
第一步:调整Flutter端交互逻辑
- 客户端触发Firebase OTP发送、用户输入验证码完成Firebase本地校验后,不要上传用户输入的明文验证码,而是获取Firebase签发的
idToken传给后端做合法性校验。 - Flutter端核心代码示例:
// 用户输入验证码后生成凭证 PhoneAuthCredential credential = PhoneAuthProvider.credential( verificationId: _verificationId, smsCode: userInputOtp ); // 完成Firebase侧本地校验 final userCredential = await FirebaseAuth.instance.signInWithCredential(credential); // 拿到校验通过后签发的ID Token final String? firebaseIdToken = await userCredential.user?.getIdToken(); // 调用自有后端校验接口 final resp = await dio.post('/api/verify-firebase-otp', data: { "phone": phoneNumber, "firebase_id_token": firebaseIdToken });
- 如果需要记录OTP发送日志,可在触发发送动作时单独调用后端接口,仅记录「某手机号于某时间触发验证码发送」即可,不需要记录验证码内容。
第二步:Laravel侧配置Firebase连接
- 项目内安装Firebase Admin SDK依赖:
composer require kreait/laravel-firebase
- 执行配置发布命令,将Firebase后台下载的服务账号密钥文件放到项目安全目录,在
.env中添加配置:
FIREBASE_CREDENTIALS=storage/secure/firebase-service-account.json FIREBASE_PROJECT_ID=你的Firebase项目ID
注意:服务账号密钥文件不要提交到公共代码仓库,设置文件权限为仅服务端运行用户可读。
第三步:编写后端校验API
- 在
routes/api.php中定义路由:
Route::post('/verify-firebase-otp', [AuthController::class, 'verifyFirebaseOtp']);
- 控制器核心校验逻辑,OTP有效性校验完全交给Firebase SDK完成,不需要做本地OTP比对:
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use Kreait\Firebase\Contract\Auth as FirebaseAuth; use App\Models\User; class AuthController extends Controller { public function __construct(protected FirebaseAuth $firebaseAuth) {} public function verifyFirebaseOtp(Request $request) { $request->validate([ 'phone' => 'required|string', 'firebase_id_token' => 'required|string' ]); try { // 校验ID Token合法性、是否在有效期内 $verifiedToken = $this->firebaseAuth->verifyIdToken($request->firebase_id_token); $firebaseUid = $verifiedToken->claims()->get('sub'); $bindPhone = $verifiedToken->claims()->get('phone_number'); // 校验Token绑定的手机号和前端上报手机号一致,防止参数伪造 if ($bindPhone !== $request->phone) { return response()->json(['code' => 400, 'msg' => '手机号信息不匹配'], 400); } // 校验通过后执行自有业务逻辑:创建/更新用户信息、签发自有登录态 $user = User::firstOrCreate( ['phone' => $request->phone], ['firebase_uid' => $firebaseUid] ); $authToken = $user->createToken('app_login')->plainTextToken; return response()->json([ 'code' => 0, 'msg' => '校验成功', 'data' => ['auth_token' => $authToken] ]); } catch (\Exception $e) { // Token过期、伪造、已作废都会进入异常分支 return response()->json(['code' => 401, 'msg' => '验证码无效或已过期,请重新获取'], 401); } } }
内容的提问来源于stack exchange,提问作者Shivesh Tripathi
相关产品推荐
相关产品推荐

