$guarded仅限制fill()等批量赋值操作,无法阻止直接赋值或Query Builder操作;需配合白名单过滤、数据库约束及强制哈希等多层防护。

为什么 $guarded 不能挡住所有修改?
因为 $guarded 只在 fill()、create()、update() 这类批量赋值操作中起作用,直接写 $model->password = 'xxx'; $model->save(); 完全绕过它。很多人以为设了 $guarded = ['password', 'is_admin'] 就高枕无忧,结果 API 接收 JSON 后用 Model::create($request->all()),敏感字段照样被塞进去。
常见错误现象:IlluminateDatabaseEloquentMassAssignmentException 没抛出,但数据库里 is_admin 被前端随便改了。
-
$guarded是白名单的反向逻辑——它声明“哪些字段不允许批量赋值”,不是“哪些字段永远不可写” - 使用场景:表单提交、API 批量创建/更新、导入脚本等依赖
fill()流程的地方 - 如果模型同时定义了
$fillable和$guarded,$fillable优先,$guarded被忽略
fill() 和 update() 时怎么确保不漏掉黑名单字段?
别信 $request->all()。哪怕模型设置了 $guarded,也要主动过滤输入。Laravel 不会帮你校验请求数据是否“干净”,只在校验通过后才执行批量赋值。
- 始终用
$request->validated()或显式白名单:$model->fill($request->only(['name', 'email'])) -
$model->update($request->all())是高危写法,等价于把整个请求体扔进fill(),哪怕$guarded存在也拦不住非法键(只要没触发 MassAssignmentException) - 注意:如果请求里有
id字段且模型没在$guarded里,update()可能意外改掉主键(尤其配合upsert()时)
数据库字段默认值和模型强制保护怎么配合?
$guarded 纯属应用层防护,数据库本身不感知。比如 password 字段设了 DEFAULT NULL,但业务上绝不允许为空,光靠 $guarded 挡不住空字符串或随机字符串写入。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 数据库加约束:
ALTER TABLE users MODIFY password VARCHAR(255) NOT NULL;+ 触发器或检查约束(如 MySQL 8.0.16+ 的CHECK (password REGEXP '^\$2y\$.{56}$')) - 模型里加
protected static $unguarded = false;强制所有模型默认启用防护(避免漏写$guarded) - 密码这类字段,应在
setPasswordAttribute()中强制哈希,而不是依赖$guarded防止写入
API 场景下最容易被忽略的绕过点
JSON API 常见的 data.attributes 结构、嵌套资源更新、PATCH 请求带部分字段——这些都可能让 $guarded 形同虚设,因为最终落到模型上的还是 fill()。
- 不要在控制器里写
User::find($id)->update($request->all()),改用$user->fill($request->validated())->save() - 批量更新多个模型时(如
User::whereIn('id', $ids)->update($data)),$guarded完全无效——这是 Query Builder 层操作,不经过 Eloquent - 测试时容易漏掉:用
factory()->create(['password' => '123'])直接构造模型,$guarded不生效,得用make()+save()才走完整流程
真正难防的不是字段名写错,而是开发者自己在某个角落调用了 fill() 却忘了过滤,或者把 Eloquent 当成 Query Builder 用。










