开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 21 天,点击查看活动详情
当管理后台功能日渐强大,使用人员和角色越来越多时,记录日志是很多必要的,可以快速索引到操作者,也能记录快照,对系统安全是有很大作用的。
Laravel 项目中可以我推荐利用中间件实现后台管理日志。
方案
- 中间件判断是否需要记录,写入队列
- 队列写入数据库
数据库设计
我们简化下,设计如下(如果你有特殊需求,可自行修改):
CREATE TABLE `admin_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`path` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`method` varchar(10) COLLATE utf8mb4_unicode_ci NOT NULL,
`ip` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
`input` text COLLATE utf8mb4_unicode_ci NOT NULL,
`created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ROW_FORMAT=DYNAMIC;
中间件
新建中间件AdminLogMiddleware:
<?php
namespace App\Http\Middleware;
use App\Jobs\OperationLogJob;
use Closure;
use Auth;
class AdminLogMiddleware
{
/**
* 处理传入的参数
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @param string $role
* @return mixed
*/
public function handle($request, Closure $next, $role)
{
// 剔除GET,OPTIONS请求
if (!in_array($method = $request->getMethod(), ['GET', 'OPTIONS'])) {
$data = [
'user_id' => Auth::guard('admin')->id(),
'path' => $request->getPathInfo(),
'method' => $method,
'ip' => $request->getClientIp(),
'input' => \json_encode($request->all(), JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE),
];
// 异步写入,提高操作流畅性
$job = (new OperationLogJob($data));
dispatch($job);
}
return $next($request);
}
}
一定要记得在需要记录日志的后台路由中加入此中间件。
我们建一个 Job 来处理这个日志,日志并不一定需要很实时,我们可以使用 ShouldQueue 延时写入:
<?php
namespace App\Jobs;
use App\Models\AdminLog;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
class OperationLogJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// 任务可以尝试的最大次数。
public $tries = 2;
// 任务可以执行的最大秒数 (超时时间)。
public $timeout = 120;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($data)
{
//
$this->queue = 'adminLog';
$this->data = $data;
}
private $data;
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
//
AdminLog::create($this->data);
}
}
当然,既然有了ShouldQueue,记得执行队列,不然白干一场.
php artisan queue:work --queue=adminLog
这样我们就完成了日志收集及写入db整一套流程了。
more
- 当然,日志并不一定非要写入数据库,写在log文件里,或者是 ES,这里就不展开了。
- 为了方便,也可以给所有后台路由统一加入 AdminLogMiddleware 中间件,把不需要做记录的路由加入配置文件,在中间件加入判断,省去在路由配置去区分是否需要记录。