hyperf 模型不支持 $fillable/$guarded,批量赋值无自动过滤,必须通过验证器校验、显式赋值或 dto 白名单手动控制字段,否则敏感字段可能被意外覆盖。

Hyperf 里没有 $fillable,别在模型里硬写
Hyperf 的模型(如 Model 或 DatabaseModel)**不支持 Laravel 风格的 $fillable 或 $guarded 属性**。你写上去也不会被框架读取或校验——它根本不会触发任何批量赋值防护逻辑。常见错误现象是:本地调试时数据能存进去,上线后突然字段丢失或报错,其实只是因为字段没被显式赋值,而非“被拦住了”。
- Hyperf 的
Model::create()和fill()方法默认接受全部传入字段,不做白名单过滤 - 即使你定义了
protected $fillable = ['name', 'email'],Hyperf 也完全无视它 - 试图复用 Laravel 项目经验直接迁移模型配置,会导致批量赋值行为不可控
真正起作用的是 validate() + 显式赋值
Hyperf 的安全边界不在模型层,而在验证器和手动赋值环节。你必须主动拦截、筛选、映射请求数据,而不是依赖模型自动过滤。
- 用
ValidationFactory做强约束校验:$validated = $this->validate($request, UserValidator::class) - 只把校验通过的字段传给模型:
$user = new User(); $user->fill($validated); - 或者更稳妥:逐字段赋值,避免
fill():$user->name = $validated['name']; $user->email = $validated['email']; - 不要用
$user->fill($request->all())—— 这等于把整个请求体裸奔塞进模型
数据库写入前必须检查字段来源
Hyperf 不阻止你往模型属性写任意值,哪怕字段不存在。但最终执行 SQL 时,未在表结构中定义的字段会被静默丢弃,而敏感字段(如 is_admin、status)可能被意外覆盖。
-
$user->is_admin = $request->input('is_admin')这种写法完全绕过任何防护,且不会报错 - 如果前端传了
id字段,又没做校验,$user->id = $request->id可能导致主键篡改 - 关联字段(如
created_by)必须由服务层注入,绝不能来自请求:$user->created_by = $this->userId() - 密码类字段务必走 mutator:
public function setPasswordAttribute(string $value): void { $this->attributes['password'] = Hash::make($value); }
复杂场景下靠 DTO + 白名单数组兜底
当接口接收嵌套结构、动态字段或需多端适配时,仅靠验证器不够。推荐用 DTO(Data Transfer Object)配合硬编码白名单数组做二次过滤。
- 定义明确字段列表:
private const ALLOWED_FIELDS = ['name', 'email', 'avatar_url']; - 过滤请求数据:
$safeInput = array_intersect_key($request->all(), array_flip(self::ALLOWED_FIELDS)); - DTO 类里不暴露 setter,只提供静态
fromArray()方法,内部做字段裁剪 - 避免用
array_filter()或unset()动态删键——容易漏掉深层嵌套字段
Hyperf 没有魔法防护层,$fillable 是个幻觉。真正的防线在你调用 fill() 之前那几行代码里:是否校验了?是否筛掉了?是否注入了可信上下文?漏掉任意一环,敏感字段就可能被写入。











