增强:聊天室内修改绑定邮箱时强制要求邮件验证码校验,并增加 60 秒发送频率限制防滥发机制
This commit is contained in:
71
app/Http/Controllers/Api/VerificationController.php
Normal file
71
app/Http/Controllers/Api/VerificationController.php
Normal file
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Api;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Models\SysParam;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Cache;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
class VerificationController extends Controller
|
||||
{
|
||||
/**
|
||||
* 发送绑定邮箱所需的验证码
|
||||
*/
|
||||
public function sendEmailCode(Request $request): JsonResponse
|
||||
{
|
||||
$request->validate([
|
||||
'email' => 'required|email'
|
||||
]);
|
||||
|
||||
$email = $request->input('email');
|
||||
$user = $request->user();
|
||||
|
||||
// 1. 检查总控制开关
|
||||
if (SysParam::where('alias', 'smtp_enabled')->value('body') !== '1') {
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => '抱歉,当前系统未开启外部邮件发信服务,请联系管理员。'
|
||||
], 403);
|
||||
}
|
||||
|
||||
// 2. 检查是否有频率限制(同一用户或同一邮箱,60秒只允许发1次)
|
||||
$throttleKey = 'email_throttle_' . $user->id;
|
||||
if (Cache::has($throttleKey)) {
|
||||
$ttl = Cache::ttl($throttleKey);
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => "发送过于频繁,请等待 {$ttl} 秒后再试。"
|
||||
], 429);
|
||||
}
|
||||
|
||||
// 3. 生成 6 位随机验证码并缓存,有效期 5 分钟
|
||||
$code = mt_rand(100000, 999999);
|
||||
$codeKey = 'email_verify_code_' . $user->id . '_' . $email;
|
||||
Cache::put($codeKey, $code, now()->addMinutes(5));
|
||||
|
||||
// 设置频率锁,过期时间 60 秒
|
||||
Cache::put($throttleKey, true, now()->addSeconds(60));
|
||||
|
||||
// 4. 执行发信动作
|
||||
try {
|
||||
Mail::raw("【飘落的流星】聊天室\n\n您正在试图绑定或修改您的验证邮箱。\n该操作的验证码为:{$code}\n打死不要告诉其他人哦!验证码5分钟内有效。", function ($msg) use ($email) {
|
||||
$msg->to($email)->subject('飘落流星聊天室 - 绑定邮箱验证码');
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'status' => 'success',
|
||||
'message' => '验证码已发送,请注意查收邮件。'
|
||||
]);
|
||||
} catch (\Throwable $e) {
|
||||
// 如果发信失败,主动接触频率限制锁方便用户下一次立重试
|
||||
Cache::forget($throttleKey);
|
||||
return response()->json([
|
||||
'status' => 'error',
|
||||
'message' => '邮件系统发送异常,请稍后再试: ' . $e->getMessage()
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,30 @@ class UserController extends Controller
|
||||
{
|
||||
$user = Auth::user();
|
||||
$data = $request->validated();
|
||||
|
||||
// 当用户试图更新邮箱,并且新邮箱不等于当前旧邮箱时启动验证码拦截
|
||||
if (isset($data['email']) && $data['email'] !== $user->email) {
|
||||
// 首先判断系统开关是否开启,没开启直接禁止修改邮箱
|
||||
if (\App\Models\SysParam::where('alias', 'smtp_enabled')->value('body') !== '1') {
|
||||
return response()->json(['status' => 'error', 'message' => '系统未开启邮件服务,当前禁止绑定/修改邮箱。'], 403);
|
||||
}
|
||||
|
||||
$emailCode = $request->input('email_code');
|
||||
if (empty($emailCode)) {
|
||||
return response()->json(['status' => 'error', 'message' => '新邮箱需要验证码,请先获取并填写验证码。'], 422);
|
||||
}
|
||||
|
||||
// 获取缓存的验证码
|
||||
$codeKey = 'email_verify_code_' . $user->id . '_' . $data['email'];
|
||||
$cachedCode = \Illuminate\Support\Facades\Cache::get($codeKey);
|
||||
|
||||
if (!$cachedCode || $cachedCode != $emailCode) {
|
||||
return response()->json(['status' => 'error', 'message' => '验证码不正确或已过期(有效期5分钟),请重新获取。'], 422);
|
||||
}
|
||||
|
||||
// 验证成功后,立即核销该验证码防止二次利用
|
||||
\Illuminate\Support\Facades\Cache::forget($codeKey);
|
||||
}
|
||||
|
||||
$user->update($data);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user