Laravel API字段隐藏无万能开关,需按场景选三类手段:模型级$hidden静态屏蔽、中间件动态过滤、Crypt加密ID;选错易致数据泄露或契约破坏。

Laravel API 字段隐藏没有“万能开关”,只有按需选择的三类手段:模型级静态屏蔽、响应级动态过滤、传输层加密伪装——选错场景轻则暴露敏感数据,重则破坏接口契约。
用 $hidden 控制模型默认输出
这是最常用也最容易误用的方式。它在模型序列化(toArray()、toJson())时自动过滤字段,但仅作用于该模型实例本身,不递归影响关联模型。
- 只对 Eloquent 模型生效,对原生数组、集合或手动构造的响应无效
- 若关联模型也有
$hidden,不会自动继承;必须各自声明 - 和
$casts冲突时,$hidden优先级更高——哪怕你把password_hash转成字符串,只要在$hidden里,照样不出现 - 示例:
class User extends Model { protected $hidden = ['password', 'remember_token', 'email_verified_at']; }
用中间件做路由级动态字段过滤
当你需要同一接口在不同场景下返回不同字段(比如管理后台要手机号,APP端不要),HideFields 中间件比改模型更灵活,但它只吃 JSON 响应原始数据,对视图响应、重定向、流式响应完全无效。
- 中间件依赖
$response->original是数组或对象,若控制器返回了Response实例(如response()->stream()),会直接报错 - 字段名区分大小写,
name和Name不是同一个键 - 不支持嵌套字段(如
profile.avatar_url),只能扁平一层 - 注册后必须带参数使用:
->middleware('hide.fields:api_token,phone')
用 Crypt::encryptString() 替代明文 ID 透传
这不是“隐藏字段”,而是让前端根本拿不到可推测的原始值。适用于表单 hidden 字段、URL 参数、分页游标等所有需要服务端可逆还原的场景。
- 绝不能对
null直接加密,否则抛出InvalidArgumentException;务必用$id ?? '0'或optional($model)->id ?? '0' - 前端拿到的是 Base64 字符串(如
eyJpdiI6Ij...),长度固定且无规律,无法反推 ID - 解密必须包裹
try/catch DecryptException,任何异常都代表请求被篡改或过期,不可忽略 - 环境变量
APP_KEY泄露 = 全量解密能力泄露,切勿提交到 Git
真正麻烦的不是怎么藏,而是藏完之后要不要校验、谁有权看、前端缓存会不会意外保留旧字段——这些不在代码里,而在每次加字段前的那句确认。










