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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 08:57:01