|
|
@@ -326,7 +326,7 @@ class SecurityMiddleware
|
|
326
|
326
|
*/
|
|
327
|
327
|
protected function handleAttack(Request $request, array $attacks): void
|
|
328
|
328
|
{
|
|
329
|
|
- $ip = $request->ip();
|
|
|
329
|
+ $ip = $this->getRealIp($request);
|
|
330
|
330
|
|
|
331
|
331
|
// 记录攻击日志
|
|
332
|
332
|
foreach ($attacks as $attack) {
|
|
|
@@ -340,6 +340,47 @@ class SecurityMiddleware
|
|
340
|
340
|
}
|
|
341
|
341
|
|
|
342
|
342
|
/**
|
|
|
343
|
+ * 获取真实客户端IP(支持Swoole模式)
|
|
|
344
|
+ */
|
|
|
345
|
+ protected function getRealIp(Request $request): string
|
|
|
346
|
+ {
|
|
|
347
|
+ $ip = '0.0.0.0';
|
|
|
348
|
+
|
|
|
349
|
+ // 1. 优先从Swoole的header中获取
|
|
|
350
|
+ if ($this->isSwooleMode()) {
|
|
|
351
|
+ // Swoole模式下,真实IP通常在x-real-ip或x-forwarded-for中
|
|
|
352
|
+ $ip = $request->header('x-real-ip', '');
|
|
|
353
|
+
|
|
|
354
|
+ if (empty($ip)) {
|
|
|
355
|
+ // 如果有多个代理,x-forwarded-for是逗号分隔的列表,取第一个
|
|
|
356
|
+ $xff = $request->header('x-forwarded-for', '');
|
|
|
357
|
+ if (!empty($xff)) {
|
|
|
358
|
+ $ips = explode(',', $xff);
|
|
|
359
|
+ $ip = trim($ips[0]);
|
|
|
360
|
+ }
|
|
|
361
|
+ }
|
|
|
362
|
+ }
|
|
|
363
|
+
|
|
|
364
|
+ // 2. 如果Swoole模式获取失败,尝试常规方法
|
|
|
365
|
+ if (empty($ip) || !filter_var($ip, FILTER_VALIDATE_IP)) {
|
|
|
366
|
+ $ip = $request->ip();
|
|
|
367
|
+ }
|
|
|
368
|
+
|
|
|
369
|
+ // 3. 验证IP格式
|
|
|
370
|
+ return filter_var($ip, FILTER_VALIDATE_IP) ? $ip : '0.0.0.0';
|
|
|
371
|
+ }
|
|
|
372
|
+
|
|
|
373
|
+ /**
|
|
|
374
|
+ * 检查是否运行在Swoole模式
|
|
|
375
|
+ */
|
|
|
376
|
+ protected function isSwooleMode(): bool
|
|
|
377
|
+ {
|
|
|
378
|
+ return extension_loaded('swoole') &&
|
|
|
379
|
+ defined('SWOOLE_VERSION') &&
|
|
|
380
|
+ (php_sapi_name() === 'cli' || isset($_SERVER['SWOOLE_SERVER']));
|
|
|
381
|
+ }
|
|
|
382
|
+
|
|
|
383
|
+ /**
|
|
343
|
384
|
* 记录攻击日志到数据库
|
|
344
|
385
|
*/
|
|
345
|
386
|
protected function logAttack(string $ip, Request $request, array $attack): void
|
|
|
@@ -449,18 +490,10 @@ class SecurityMiddleware
|
|
449
|
490
|
*/
|
|
450
|
491
|
protected function blockResponse(): Response
|
|
451
|
492
|
{
|
|
452
|
|
- throw new \Exception('访问被拒绝', 403);
|
|
453
|
|
- // return response()
|
|
454
|
|
- // ->json([
|
|
455
|
|
- // 'code' => 403,
|
|
456
|
|
- // 'message' => '访问被拒绝',
|
|
457
|
|
- // 'data' => null
|
|
458
|
|
- // ])
|
|
459
|
|
- // ->code(403)
|
|
460
|
|
- // ->header([
|
|
461
|
|
- // 'Content-Type' => 'application/json',
|
|
462
|
|
- // 'Retry-After' => 3600
|
|
463
|
|
- // ]);
|
|
|
493
|
+ return Response::create([
|
|
|
494
|
+ 'code' => 403,
|
|
|
495
|
+ 'msg' => '访问被拒绝'
|
|
|
496
|
+ ], 'json')->code(403);
|
|
464
|
497
|
}
|
|
465
|
498
|
|
|
466
|
499
|
/**
|
|
|
@@ -468,13 +501,9 @@ class SecurityMiddleware
|
|
468
|
501
|
*/
|
|
469
|
502
|
protected function errorResponse(): Response
|
|
470
|
503
|
{
|
|
471
|
|
- throw new \Exception('请求参数错误', 400);
|
|
472
|
|
- // return response()
|
|
473
|
|
- // ->json([
|
|
474
|
|
- // 'code' => 400,
|
|
475
|
|
- // 'message' => '请求参数错误',
|
|
476
|
|
- // 'data' => null
|
|
477
|
|
- // ])
|
|
478
|
|
- // ->code(400);
|
|
|
504
|
+ return Response::create([
|
|
|
505
|
+ 'code' => 400,
|
|
|
506
|
+ 'msg' => '请求参数错误'
|
|
|
507
|
+ ], 'json')->code(400);
|
|
479
|
508
|
}
|
|
480
|
509
|
}
|