正确使用验证时是否需要批量分配保护?
Is mass assignment protection needed when properly using validation?
我一直在使用 Laravel (5.4) 和 PHP 这两个都是我第一次在我负责维护的遗留应用程序中,在过去的几个月里我注意到一个痛点,就是批量赋值
我相信我对什么是什么已经有了足够的了解,但我不确定我是否真的正确地使用了它。 The official documentation 使用用户角色的(好的但极端的)示例来说明问题。我理解这一点的重要性以及为什么我应该保护这些变量。但是,一般来说,我不认为我真的对确定要保护或不保护哪些字段(如果有的话)有深入的了解。
似乎 Laravel 的很多不错的功能似乎都没有考虑到批量赋值,这是我沮丧的主要原因。例如,如果我的端点有一些可选字段(即您可以不在请求中指定它们),那么执行 mymodel->update(request->all())
只会更新您提供的字段。如果许多字段都受到保护,如果我想实现相同的行为,我将不得不多次重复 isset() 检查,这似乎是不必要的。 我也知道request->all()
不应该这么用,但我只是想说明一点。
当您考虑到您可能会使用稳健的验证以及诸如 request->only([...])
之类的东西来确保您的数据正确并仅过滤到您期望的内容时,它会变得更加麻烦。
所以最终我要问的是:
在存在稳健的验证和输入整形方法的情况下,批量分配几乎还有什么值得做的吗?总的来说,当我的验证步骤似乎已经解决了这个问题时,我似乎无缘无故地跳过了这么多箍。 如果它仍然值得做,我还缺少什么?批量分配保护是否应该只委托给超级重要的字段,比如用户的角色,而不是其他?
其实我没明白你这句话的意思:
If many of the fields were guarded, I would have to have many repeated
isset() checks if I wanted to achieve the same behavior
不是可批量分配的字段,只是在请求中出现时被丢弃
但是在用户从请求中传递 forbidden_param
之类的参数并且 forbidden_param
不可批量分配 的情况下(要么不在填充物中,要么它在守卫中)不会抛出任何错误,eloquent 将 discard forbidden_param
.
如果你的代码中有这个:
if(isset($request->forbidden_param))
你可以从他们那里得到解脱,当使用质量分配时。
Laravel 随心所欲
Laravel 只是不强迫你使用 helpers 或 Facade 或 DI , ... 使用服务。
为了保护模型字段,您可以使用不同的解决方案来:
1.Eloquent 保护(可批量分配)
您可以从请求中传递参数,然后保护它们免受 eloquent.
//in controller
MyModel::update($request->input())
// in model
$fillable = [ ... ]
//or
$guarded = [ ... ]
这是一个常见的模式,我已经看到很多代码使用这种情况。
好处是:
- 倾斜控制器
- 如果您只是忘记在其他地方(控制器/验证)控制输入,不用担心容易出错的字段
2.Controller保护
我看到的另一种模式是在控制器中的 update
方法中放置确切的参数。
Model::update([
'permitted_param1' => $request->permitted_param
'permitted_param2' => $request->permitted_param2
]);
在这种情况下,可以通过以下方式放宽模型中可分配的质量:
$guarded = [];
或者可以使它受益,以防另一个控制器上的另一个队友可能忘记控制输入并使用 $request->input()
。
不过这是可选的。
这样做的好处:
- 能够具有不同的输入名称和数据库字段名称
- 能够在输入模型之前操纵输入(这可以使用 mutators 或 repository 实现)。但如果要更改的字段很少,则实施起来更简单。
在下面的示例中,控制器使用混合方法:
User::create($request->except('password') + [ 'secret' => bcrypt($request->password)] );
3.Protecting 在验证器中
我见过的最有前途的方法之一是仅使用经过验证的数据,如下所示:
对于 Laravel 8+:
MyModel::update($request->safe()->all());
和 Laravel 在 8 之前:
MyModel::update($request->validated())
你可以放宽 批量分配
好处:
- 您已将验证数据和敏感数据合并到一处
- 更精简的控制器
- 您确定已验证所有数据
Note: in case of optional data you can just not to put the required
rule
4.Repository 模式
另一种方法是使用 存储库模式,这会给小项目带来复杂性。
但结果是:
- 更精简的控制器和模型
- 在存储库中移动查询逻辑
- 使查询更具可重用性和解耦性
对于使用此设计模式的项目,此控件可以移至存储库。
我一直在使用 Laravel (5.4) 和 PHP 这两个都是我第一次在我负责维护的遗留应用程序中,在过去的几个月里我注意到一个痛点,就是批量赋值
我相信我对什么是什么已经有了足够的了解,但我不确定我是否真的正确地使用了它。 The official documentation 使用用户角色的(好的但极端的)示例来说明问题。我理解这一点的重要性以及为什么我应该保护这些变量。但是,一般来说,我不认为我真的对确定要保护或不保护哪些字段(如果有的话)有深入的了解。
似乎 Laravel 的很多不错的功能似乎都没有考虑到批量赋值,这是我沮丧的主要原因。例如,如果我的端点有一些可选字段(即您可以不在请求中指定它们),那么执行 mymodel->update(request->all())
只会更新您提供的字段。如果许多字段都受到保护,如果我想实现相同的行为,我将不得不多次重复 isset() 检查,这似乎是不必要的。 我也知道request->all()
不应该这么用,但我只是想说明一点。
当您考虑到您可能会使用稳健的验证以及诸如 request->only([...])
之类的东西来确保您的数据正确并仅过滤到您期望的内容时,它会变得更加麻烦。
所以最终我要问的是:
在存在稳健的验证和输入整形方法的情况下,批量分配几乎还有什么值得做的吗?总的来说,当我的验证步骤似乎已经解决了这个问题时,我似乎无缘无故地跳过了这么多箍。 如果它仍然值得做,我还缺少什么?批量分配保护是否应该只委托给超级重要的字段,比如用户的角色,而不是其他?
其实我没明白你这句话的意思:
If many of the fields were guarded, I would have to have many repeated isset() checks if I wanted to achieve the same behavior
不是可批量分配的字段,只是在请求中出现时被丢弃
但是在用户从请求中传递 forbidden_param
之类的参数并且 forbidden_param
不可批量分配 的情况下(要么不在填充物中,要么它在守卫中)不会抛出任何错误,eloquent 将 discard forbidden_param
.
如果你的代码中有这个:
if(isset($request->forbidden_param))
你可以从他们那里得到解脱,当使用质量分配时。
Laravel 随心所欲
Laravel 只是不强迫你使用 helpers 或 Facade 或 DI , ... 使用服务。
为了保护模型字段,您可以使用不同的解决方案来:
1.Eloquent 保护(可批量分配)
您可以从请求中传递参数,然后保护它们免受 eloquent.
//in controller
MyModel::update($request->input())
// in model
$fillable = [ ... ]
//or
$guarded = [ ... ]
这是一个常见的模式,我已经看到很多代码使用这种情况。
好处是:
- 倾斜控制器
- 如果您只是忘记在其他地方(控制器/验证)控制输入,不用担心容易出错的字段
2.Controller保护
我看到的另一种模式是在控制器中的 update
方法中放置确切的参数。
Model::update([
'permitted_param1' => $request->permitted_param
'permitted_param2' => $request->permitted_param2
]);
在这种情况下,可以通过以下方式放宽模型中可分配的质量:
$guarded = [];
或者可以使它受益,以防另一个控制器上的另一个队友可能忘记控制输入并使用 $request->input()
。
不过这是可选的。
这样做的好处:
- 能够具有不同的输入名称和数据库字段名称
- 能够在输入模型之前操纵输入(这可以使用 mutators 或 repository 实现)。但如果要更改的字段很少,则实施起来更简单。
在下面的示例中,控制器使用混合方法:
User::create($request->except('password') + [ 'secret' => bcrypt($request->password)] );
3.Protecting 在验证器中
我见过的最有前途的方法之一是仅使用经过验证的数据,如下所示: 对于 Laravel 8+:
MyModel::update($request->safe()->all());
和 Laravel 在 8 之前:
MyModel::update($request->validated())
你可以放宽 批量分配
好处:
- 您已将验证数据和敏感数据合并到一处
- 更精简的控制器
- 您确定已验证所有数据
Note: in case of optional data you can just not to put the
required
rule
4.Repository 模式
另一种方法是使用 存储库模式,这会给小项目带来复杂性。
但结果是:
- 更精简的控制器和模型
- 在存储库中移动查询逻辑
- 使查询更具可重用性和解耦性
对于使用此设计模式的项目,此控件可以移至存储库。