在 Laravel 12 中实现手机号验证

在 Laravel 12 中实现手机号验证,可以通过以下步骤完成完整的验证流程(包含格式验证、唯一性验证和短信验证):


1. 数据库准备

确保 users 表包含已验证手机号字段:

// database/migrations/xxxxx_add_phone_to_users_table.php
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->nullable()->comment('手机号');
    $table->timestamp('phone_verified_at')->nullable()->comment('验证时间');
});

2. 创建验证规则

方法 1:使用 FormRequest

创建注册验证请求类:

php artisan make:request RegisterRequest

app/Http/Requests/RegisterRequest.php

public function rules()
{
    return [
        'phone' => [
            'required',
            'regex:/^\+?[1-9]\d{8,14}$/', // 国际手机号格式(含国家码)
            'unique:users,phone'
        ],
        'sms_code' => 'required|digits:6'
    ];
}

public function messages()
{
    return [
        'phone.regex' => '手机号格式无效,示例:+8613123456789',
        'sms_code.digits' => '验证码必须是6位数字'
    ];
}
方法 2:直接验证

在控制器中验证:

$validated = $request->validate([
    'phone' => 'required|regex:/^\+?[1-9]\d{8,14}$/|unique:users,phone',
    'sms_code' => 'required|digits:6'
]);

3. 手机号预处理中间件(可选)

自动清理格式:

// app/Http/Middleware/FormatPhone.php
public function handle(Request $request, Closure $next)
{
    if ($request->has('phone')) {
        $phone = preg_replace('/[^0-9+]/', '', $request->phone);
        $request->merge(['phone' => $phone]);
    }
    
    return $next($request);
}

注册中间件到 Kernel.php

protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\FormatPhone::class,
        // ...
    ]
];

4. 短信验证集成

发送验证码接口
// routes/api.php
Route::post('/send-sms', function (Request $request) {
    $request->validate(['phone' => 'required|regex:/^\+?[1-9]\d{8,14}$/']);

    // 生成6位随机码并缓存(有效期5分钟)
    $code = str_pad(random_int(0, 999999), 6, '0', STR_PAD_LEFT);
    Cache::put('sms_code:'.$request->phone, $code, 300); 

    // 调用短信服务(示例用阿里云)
    AlibabaCloud::sms()
        ->send()
        ->withPhoneNumbers($request->phone)
        ->withSignName('YourApp')
        ->withTemplateCode('SMS_123456')
        ->withTemplateParam(json_encode(['code' => $code]))
        ->send();

    return response()->json(['message' => '验证码已发送']);
});
验证码校验逻辑

在控制器中添加:

protected function verifySmsCode($phone, $code)
{
    $cachedCode = Cache::pull('sms_code:'.$phone);
    return $cachedCode && $cachedCode === $code;
}

5. 验证流程示例

注册控制器逻辑
// app/Http/Controllers/Auth/RegisterController.php
public function register(RegisterRequest $request)
{
    // 验证短信验证码
    if (!$this->verifySmsCode($request->phone, $request->sms_code)) {
        return back()->withErrors(['sms_code' => '验证码错误或已过期']);
    }

    // 创建用户
    $user = User::create([
        'phone' => $request->phone,
        'phone_verified_at' => now(),
        // 其他字段...
    ]);

    // 自动登录或重定向
    auth()->login($user);
    return redirect('/dashboard');
}

6. 验证状态检查

在用户模型中添加验证状态判断:

// app/Models/User.php
public function hasVerifiedPhone()
{
    return !is_null($this->phone_verified_at);
}

public function markPhoneAsVerified()
{
    $this->forceFill([
        'phone_verified_at' => $this->freshTimestamp(),
    ])->save();
}

7. 测试用例

验证主要场景:

// tests/Feature/PhoneVerificationTest.php
public function test_phone_verification_flow()
{
    // 测试无效格式
    $response = $this->post('/register', [
        'phone' => '1381234', // 错误格式
        'sms_code' => '123456'
    ]);
    $response->assertSessionHasErrors(['phone']);

    // 测试验证码错误
    $response = $this->post('/register', [
        'phone' => '+8613812345678',
        'sms_code' => 'wrong_code'
    ]);
    $response->assertSessionHasErrors(['sms_code']);

    // 测试成功注册
    Cache::put('sms_code:+8613812345678', '123456');
    $response = $this->post('/register', [
        'phone' => '+8613812345678',
        'sms_code' => '123456'
    ]);
    $this->assertAuthenticated();
}

8. 前端展示优化

在 Blade 模板中添加验证状态提示:

<!-- resources/views/profile/phone-verify.blade.php -->
@if (auth()->user()->hasVerifiedPhone())
    <div class="alert alert-success">
        手机号已验证:{{ auth()->user()->phone }}
    </div>
@else
    <div class="alert alert-warning">
        您的手机号未验证,<a href="{{ route('verify.phone') }}">立即验证</a>
    </div>
@endif

扩展功能建议

  1. 防刷机制:限制同一IP/手机号的短信发送频率
// app/Http/Middleware/ThrottleSms.php
RateLimiter::for('sms', function (Request $request) {
    return Limit::perMinute(1)->by($request->ip().'|'.$request->phone);
});
  1. 多渠道验证:支持语音验证码备用方案

  2. 国际化支持:根据国家代码自动匹配验证规则

通过以上实现,可以完成以下功能:

  • ✅ 国际标准手机号格式验证
  • ✅ 短信验证码发送与校验
  • ✅ 防恶意请求保护
  • ✅ 验证状态持久化记录
  • ✅ 友好的错误提示系统
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值