You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

72 lines
2.2 KiB

<?php
namespace App\Http\Middleware;
use App\Models\AdminUser;
use App\Models\OperationLog;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Symfony\Component\HttpFoundation\Response;
class LogAdminOperation
{
public function handle(Request $request, Closure $next): Response
{
$start = microtime(true);
/** @var Response $response */
$response = $next($request);
$user = $request->user();
if (! $user instanceof AdminUser) {
// 登录接口在认证前执行,日志在 AuthController 内单独写入
return $response;
}
$method = strtoupper($request->method());
if (! in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)) {
return $response;
}
$path = '/'.$request->path();
if (Str::contains($path, '/operation-logs') && $method === 'GET') {
return $response;
}
if (Str::contains($path, '/auth/me')) {
return $response;
}
$summary = $this->sanitizeRequest($request);
OperationLog::query()->create([
'admin_user_id' => $user->id,
'operator_name' => $user->real_name ?: $user->username,
'operated_at' => now(),
'http_method' => $method,
'api_path' => $path,
'action_label' => $request->route()?->getName() ?? ($method.' '.$path),
'ip' => $request->ip(),
'user_agent' => Str::limit((string) $request->userAgent(), 512, ''),
'request_summary' => $summary,
'response_code' => $response->getStatusCode(),
'duration_ms' => (int) round((microtime(true) - $start) * 1000),
]);
return $response;
}
/**
* @return array<string, mixed>|null
*/
protected function sanitizeRequest(Request $request): ?array
{
$data = $request->except(['password', 'password_hash', 'password_confirmation', 'token', 'current_password', 'file']);
$encoded = json_encode($data);
if ($encoded === false) {
return null;
}
return json_decode(Str::limit($encoded, 4000, '...'), true);
}
}