最轻量的管理员操作留痕方式是用 Model Observer 监听 Eloquent 增删改事件,配合中间件兜底非模型操作,禁用 DB::listen() 和 general_log;需注意事务回滚日志不自动撤销。

怎么用 Laravel 的 Model Observer 记录管理员操作
直接用 Observer 监听模型的增删改事件,是最轻量、侵入性最小的留痕方式。它不依赖中间件或请求生命周期,只要模型被 Eloquent 操作,就能捕获——但前提是操作必须走 Eloquent,绕过 Query Builder 或原生 SQL 就会漏掉。
- 在
app/Observers/AdminActivityObserver.php里定义观察器,监听created、updated、deleted等方法 - 每个方法里调用
Auth::check()判断是否为后台管理员,再用Auth::id()获取操作人 ID - 记录字段建议包含:
user_id、action(如 "updated")、model_type(get_class($model))、model_id、old_values和new_values(用$model->getOriginal()和$model->getChanges()提取) - 注意:软删除触发的是
deleted,不是deleting;如果要记录「逻辑删除」动作,得监听deleting并手动判断$model->isForceDeleting() === false
Laravel 中间件里记录非模型操作(比如导出、审核通过)
有些关键行为根本不碰数据库模型,比如点击「批量导出 Excel」或「一键审核通过」,这时候 Observer 失效,必须靠中间件兜底。
- 写一个
LogAdminActionMiddleware,在handle()里用request()->route()->getName()或request()->route()->action['as']匹配路由名(如admin.orders.approve) - 对敏感路由做白名单判断,避免日志爆炸;不要用
request()->url(),容易因参数顺序不同导致重复记录 - 记录前检查
Auth::guard('admin')->check(),Laravel 后台通常用独立 guard,别错用webguard - 别在中间件里做耗时操作(如写文件、发 HTTP 请求),一律丢进队列;用
Log::channel('admin_activity')->info(...)写到专用日志通道更稳妥
为什么不能只靠 DB::listen() 全局监听 SQL
看起来很省事,但实际几乎不可用。它能抓到所有查询,却无法关联用户、上下文和业务语义。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
-
DB::listen()回调里拿不到当前请求的用户信息,除非你手动把Auth::id()绑定到DB::connection()的属性上——这既不安全也不稳定 - 一条 Eloquent
save()可能触发多条 SQL(INSERT + UPDATE + INSERT IGNORE),你根本分不清哪条对应哪个业务动作 - 大量日志会拖慢响应,尤其在高并发导出场景下,
DB::listen()是同步执行的,没缓冲没队列 - MySQL 的 general_log 更危险:它记录所有连接的所有语句,包括系统探活、健康检查,日志体积暴涨且含敏感字段值(如明文密码字段)
日志表设计要注意哪些兼容性坑
留痕数据要长期可查,表结构不能只图快,得考虑后期加字段、跨库查询、归档清理。
-
model_id必须是BIGINT UNSIGNED,否则碰到大整数 ID(如雪花算法生成的)会溢出或截断 - 别用
TEXT存old_values/new_values,统一用JSON类型(MySQL 5.7+ / PostgreSQL),便于后续用 JSON 函数查变更字段 - 加复合索引:
(user_id, created_at)支持按人查操作时间线;(model_type, model_id)支持追溯某条记录的所有操作 - 如果未来要支持多 guard(如 admin + api_admin),
guard_name字段不能省,别硬编码成 "admin"
事情说清了就结束。最常被忽略的是:Observer 不处理事务回滚后的状态,如果业务里用了 DB::transaction() 且中途失败,Observer 已经发出去的日志不会自动撤销——得靠补偿任务或日志状态字段来兜底。










