必须设 $fillable 或 $guarded,否则 create()、fill()、update() 可能将 is_admin 等敏感字段写入数据库;验证器只校验格式合法性,不控制字段是否允许赋值,而 $fillable 是模型层白名单,未列出字段被静默丢弃,安全性远高于 $guarded 黑名单。

必须设 $fillable 或 $guarded,否则 create()、fill()、update() 都可能把 is_admin、role_id、balance 这类字段一起写进数据库——验证器拦不住,它只管格式对不对,不管该不该改。
为什么验证器不能替代 $fillable
验证器检查的是“数据合不合法”,比如 email 是不是邮箱格式、password 长度够不够;但它不阻止你传一个 is_admin=1 进来——只要没在规则里显式禁止,它就默认放行。而 $fillable 是模型层的“开关”,不在白名单里的字段,Eloquent 根本不会碰,连赋值动作都不会发生。
- 验证器失败会抛异常或返回错误,
$fillable拦截是静默丢弃,不报错也不警告 -
FormRequest可以用validated()过滤字段,但如果你直接用$request->all()传给create(),过滤就失效了 - 同一个模型可能被多个控制器、命令、API 调用,靠每个地方手动
only()容易漏,$fillable是统一防线
$fillable 和 $guarded 到底选哪个
优先用 $fillable,明确列出允许批量赋值的字段;$guarded 容易误判,比如设成 ['id', 'created_at'],结果忘了加 is_admin,漏洞就出来了。
-
$fillable = ['name', 'email', 'phone']:只这三项能进,其余全丢,最安全 -
$guarded = ['is_admin', 'role_id']:只要字段名没列在$guarded里,就都能进,风险更高 - 两个同时定义时,
$guarded优先级更高,但不建议混用,容易混乱 - 别写
$fillable = []或$guarded = [],空数组 ≠ 全部禁止/全部允许,Laravel 会当成未设置,走默认不保护逻辑
哪些方法实际触发批量赋值防护
只有走 Eloquent 模型实例化或属性填充路径的方法才受 $fillable 控制;绕过模型直连查询的,防护无效。
- 受控:
User::create($data)、$user->fill($data)、$user->update($data) - 不受控:
User::where(...)->update($data)(这是 Query Builder 操作,跳过模型层) - 不受控:
DB::table('users')->insert($data)(完全绕过 Eloquent) - 注意:
updateOrCreate()和firstOrCreate()也走模型填充,受$fillable约束
真正容易被忽略的是:$guarded = ['*'] 并不等价于“全部禁止”——它只禁掉显式声明的字段,如果模型里还有动态属性或通过 setAttribute() 注入的字段,仍可能被写入。白名单才是唯一可靠的基线。











