应使用$hidden数组、访问器或API资源类控制敏感字段输出,$hidden仅影响序列化,访问器适合权限动态控制,资源类最灵活且解耦;$casts和setXxxAttribute不控制读取。

模型里用 $hidden 控制字段不被序列化输出
想让 User 模型的 password、remember_token 从 toArray() 或 API 返回里彻底消失,直接在模型里写 $hidden 数组就行。它只影响序列化行为,不影响数据库读写本身。
常见错误是把敏感字段漏写进 $hidden,比如忘了 api_token 或自定义的 temp_key;或者误写成 $guarded——那玩意儿管的是批量赋值,跟输出无关。
$hidden = ['password', 'remember_token', 'api_token']- 如果只想对某次查询隐藏,用
makeHidden(['field']),比如User::first()->makeHidden(['email']) - 注意:
$hidden对 Eloquent 关系(如posts)里的字段无效,得在关联模型里单独设
用 getAttribute 动态拦截字段读取
有些字段不是永远不能读,而是要看当前用户权限或请求上下文——比如普通用户不能看 balance,但管理员可以。这时候不能靠静态 $hidden,得重写 getAttribute。
直接改这个方法风险高:它会被所有属性访问触发,包括内部用的 id、created_at 等,一不小心就破坏框架逻辑。
- 优先用访问器(accessor):写
getBalanceAttribute(),里面加权限判断,返回null或抛异常 - 如果必须全局拦截,重写时先
if (in_array($key, $restricted)) { ... },再调用parent::getAttribute($key),别漏掉父类逻辑 - 注意:
getAttribute不影响$model->balance的直接访问,但会影响data_get($model, 'balance')和数组展开
API 响应时用资源类(Resource)做最终过滤
控制器里直接 return new UserResource($user),比在模型里硬控更灵活。资源类天然隔离了“数据怎么查”和“数据怎么发”,也方便不同接口返回不同字段。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
容易踩的坑是把资源类当万能胶水,把权限判断、业务逻辑全塞进去,结果资源变重、难测试、复用率低。
- 资源类里用
$this->when(...)控制字段条件输出,比如$this->when(auth()->user()?->is_admin, 'balance') - 不要在
toArray()里查数据库或调用耗时方法,资源类应该轻量 - 如果前端要分页列表,记得在集合资源里统一控制,别每个模型单独处理
$casts 和 setXxxAttribute 不解决读取控制问题
有人试过把 password 设为 string:hashed 或写 setPasswordAttribute,以为能防读——其实完全没用。这些只影响写入和类型转换,$user->password 依然能直接拿到哈希值。
更隐蔽的问题是:用 appends 加的访问器字段(如 is_active)默认也会出现在 JSON 里,如果它依赖敏感计算,得手动在资源里关掉或用 makeHidden 补救。
-
$casts是类型转换工具,不是访问门禁 -
setXxxAttribute只在赋值时触发,对读取无约束力 - 真正需要读取控制的地方,只有三处:模型
$hidden、访问器、资源类——别往别的地方试了
最麻烦的其实是嵌套关系和动态字段:比如 User::with('profile')->get(),profile 模型的隐藏规则不会自动继承,得各自配置;还有通过 selectRaw 或 DB::raw 加的字段,根本绕过模型层,$hidden 完全无效。










