如何检测Laravel auth()->user()对象特定字段的值变更
Laravel中检测auth()->user()特定字段变更的实现方案
你想通过会话存旧值的思路完全可行,找不到赋值位置核心是没用到框架自带的认证生命周期钩子,不需要在业务代码里到处插埋点,下面是可直接落地的实现:
方案1:基于认证事件+会话实现跨请求变更检测(适配第三方CMS改数据场景)
这个方案完全匹配你的业务场景,不管是第三方系统改了库数据,还是你主动刷新用户实例,都能准确捕获变更:
- 首先注册两个认证事件的监听器,不用改现有业务逻辑:
- 监听登录事件:用户首次登录成功时,把监控字段的初始值写入会话
// App\Listeners\StoreOldUserFieldOnLogin 监听器 public function handle(\Illuminate\Auth\Events\Login $event) { if ($event->guard === 'web') { // 把你要监控的字段替换成实际字段名,这里以vip等级字段为例 session(['_user_vip_level_old' => $event->user->vip_level]); } }- 监听认证通过事件:每次请求初始化认证态、手动调用refresh刷新用户实例时都会触发,在这里做新旧值对比
// App\Listeners\CheckUserFieldChangeOnAuth 监听器 public function handle(\Illuminate\Auth\Events\Authenticated $event) { if ($event->guard !== 'web') return; $oldValue = session('_user_vip_level_old'); $newValue = $event->user->vip_level; // 首次登录没有旧值不做判断,值不一致时触发变更逻辑 if (!is_null($oldValue) && $oldValue != $newValue) { // 这里写字段变更后的业务逻辑:比如弹权益变更提示、发站内信、清缓存 // 处理完成后更新会话里的旧值,避免下次请求重复触发 session(['_user_vip_level_old' => $newValue]); } }
记得把两个监听器注册到EventServiceProvider的$listen数组里对应事件下即可生效。
方案2:基于模型钩子实现单请求内变更检测(无会话场景可用)
如果你只需要在当前请求里主动刷新用户时检测变更,完全不用存会话,直接用Eloquent自带的能力就行:
$user = auth()->user(); // 先取当前内存里的旧值 $oldFieldValue = $user->target_field; // 从数据库拉取最新数据覆盖当前实例 $user->refresh(); // 直接对比 if ($oldFieldValue !== $user->target_field) { // 执行变更后逻辑 }
全局生效的话可以直接在User模型里注册refreshed钩子,不用每次手动写对比逻辑:
// App\Models\User 模型 protected static function booted() { static::refreshed(function (User $user) { // getOriginal()直接取刷新前内存中存的原始值,不需要额外存 $oldValue = $user->getOriginal('target_field'); if ($oldValue !== $user->target_field) { // 变更处理逻辑 } }); }
这个方案适合API无状态场景,缺点是只能捕获当前请求生命周期内的刷新操作,跨请求的第三方修改检测还是要用方案1。
常见坑点
- 别把旧值存在模型静态变量、请求上下文里,PHP请求结束后这些值会销毁,跨请求检测不到第三方改的数据
- 对比json、枚举类型字段时记得用严格等于
===,避免类型隐式转换导致的误判 - 如果用了多guard认证,一定要判断当前guard,避免把后台管理员、其他端用户的字段值存错会话
内容的提问来源于stack exchange,提问作者Stephen Aiena
相关产品推荐
相关产品推荐

