Laravel 10注册按钮集成OTP手机验证求助
实现Laravel 10注册流程的OTP手机验证方案
以下是分步实现方案,帮你将短信OTP验证整合到注册流程中:
1. 为用户表添加OTP相关字段
首先需要在用户表中存储OTP验证码、过期时间和验证状态:
php artisan make:migration add_otp_fields_to_users_table
编辑生成的迁移文件:
<?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { public function up() { Schema::table('users', function (Blueprint $table) { $table->string('otp_code')->nullable(); $table->timestamp('otp_expires_at')->nullable(); $table->boolean('is_verified')->default(false); }); } public function down() { Schema::table('users', function (Blueprint $table) { $table->dropColumn(['otp_code', 'otp_expires_at', 'is_verified']); }); } };
执行迁移:
php artisan migrate
更新User模型的$fillable属性:
protected $fillable = [ 'name', 'phone', 'password', 'otp_code', 'otp_expires_at', 'is_verified', ];
2. 修改RegisterController逻辑
重写注册流程,先创建未验证用户并发送OTP,再跳转验证页面:
<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use App\Providers\RouteServiceProvider; use App\Models\User; use Illuminate\Foundation\Auth\RegistersUsers; use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Validator; use Illuminate\Http\Request; use Illuminate\Support\Facades\Session; use SoapClient; class RegisterController extends Controller { use RegistersUsers; protected $redirectTo = RouteServiceProvider::HOME; public function __construct() { $this->middleware('guest'); } protected function validator(array $data) { return Validator::make($data, [ 'name' => ['required', 'string', 'min:10', 'unique:users'], 'password' => ['required', 'string', 'min:8', 'confirmed'], 'phone' => ['required', 'string', 'max:11', 'unique:users'], ]); } // 重写注册方法 public function register(Request $request) { $this->validator($request->all())->validate(); // 生成6位OTP验证码,有效期5分钟 $otpCode = rand(100000, 999999); $otpExpiresAt = now()->addMinutes(5); // 创建未验证状态的用户 $user = User::create([ 'name' => $request->name, 'phone' => $request->phone, 'password' => Hash::make($request->password), 'otp_code' => $otpCode, 'otp_expires_at' => $otpExpiresAt, 'is_verified' => false, ]); // 发送OTP短信 $this->sendOtpSms($request->phone, $otpCode); // 存储用户ID到会话,用于后续验证 Session::put('verification_user_id', $user->id); // 跳转到OTP验证页面 return redirect()->route('otp.verify')->with('success', 'کد تایید به شماره تلفن شما ارسال شد'); } // 短信发送逻辑 private function sendOtpSms($phoneNumber, $otpCode) { ini_set("soap.wsdl_cache_enabled", "0"); try { $sms_client = new SoapClient('http://payamak-service.ir/SendService.svc?wsdl', array('encoding'=>'UTF-8')); $parameters = [ 'userName' => '你的用户名', // 替换为短信服务用户名 'password' => '你的密码', // 替换为短信服务密码 'fromNumber' => '你的发送号码', // 替换为短信服务提供的发送号码 'toNumbers' => [$phoneNumber], 'messageContent' => "کد تایید شما برای ثبت نام در سایت 50 نکته: $otpCode", 'isFlash' => false, 'recId' => [0], 'status' => 0x0, ]; $recId = &$parameters['recId']; $status = &$parameters['status']; $sms_client->SendSMS($parameters)->SendSMSResult; } catch (\Exception $e) { // 短信发送失败时可以删除已创建的用户并抛出错误 User::where('phone', $phoneNumber)->delete(); throw new \Exception('خطا در ارسال کد تایید، لطفا دوباره تلاش کنید'); } } // 显示OTP验证页面 public function showOtpVerificationForm() { if (!Session::has('verification_user_id')) { return redirect()->route('register')->with('error', 'لطفا ابتدا ثبت نام کنید'); } return view('auth.otp-verify'); } // 验证OTP逻辑 public function verifyOtp(Request $request) { $request->validate([ 'otp_code' => 'required|digits:6', ]); $userId = Session::get('verification_user_id'); $user = User::findOrFail($userId); // 检查OTP是否有效且未过期 if ($user->otp_code !== $request->otp_code || now()->greaterThan($user->otp_expires_at)) { return back()->with('error', 'کد تایید نامعتبر یا منقضی شده است'); } // 标记用户为已验证 $user->update([ 'is_verified' => true, 'otp_code' => null, 'otp_expires_at' => null, ]); // 清除会话并登录用户 Session::forget('verification_user_id'); $this->guard()->login($user); return redirect()->route('home')->with('success', 'ثبت نام با موفقیت انجام شد'); } }
3. 添加OTP验证路由
在routes/web.php中添加验证路由:
Route::get('/otp/verify', [App\Http\Controllers\Auth\RegisterController::class, 'showOtpVerificationForm'])->name('otp.verify'); Route::post('/otp/verify', [App\Http\Controllers\Auth\RegisterController::class, 'verifyOtp'])->name('otp.verify.submit');
4. 创建OTP验证页面
在resources/views/auth/下创建otp-verify.blade.php:
@extends('layouts.app') @section('content') <form method="POST" class="py-3 px-md-5 px-3" action="{{ route('otp.verify.submit') }}"> @csrf <h3>تایید شماره تلفن</h3> @if (session('success')) <div class="alert alert-success text-end"> {{ session('success') }} </div> @endif @if (session('error')) <div class="alert alert-danger text-end"> {{ session('error') }} </div> @endif <div class="row mb-3"> <div class="col-md-12"> <input id="otp_code" type="text" placeholder="کد تایید 6 رقمی" name="otp_code" required autocomplete="off" maxlength="6"> @error('otp_code') <span class="invalid-feedback text-end mt-2" role="alert"> <strong class="text-danger_cs" dir="rtl">{{ $message }}</strong> </span> @enderror </div> </div> <div class="row mb-0"> <div class="col-md-12 text-center"> <button type="submit" class="btn bg-danger_cs w-75 mt-0 text-white p-2"> تایید کد </button> </div> </div> </form> @endsection
5. 修改注册表单
移除提交按钮上无效的onclick="sms()"事件:
<button type="submit" class="btn bg-danger_cs w-75 mt-0 text-white p-2"> {{ __('ثبتنام') }} </button>
注意事项
- 确保服务器已启用PHP Soap扩展(可通过
php -m | grep soap检查) - 替换短信服务中的用户名、密码和发送号码为你的实际信息
- 可添加OTP重发功能:在验证页面添加按钮,调用重新生成OTP并发送的方法
- 可在登录逻辑中添加未验证用户拦截,强制完成OTP验证
内容的提问来源于stack exchange,提问作者dariush nasr
相关产品推荐
相关产品推荐

