正确使用验证时是否需要批量分配保护?

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 不可批量分配 的情况下(要么不在填充物中,要么它在守卫中)不会抛出任何错误,eloquentdiscard forbidden_param .

如果你的代码中有这个:

if(isset($request->forbidden_param))

你可以从他们那里得到解脱,当使用质量分配时。

Laravel 随心所欲

Laravel 只是不强迫你使用 helpersFacadeDI , ... 使用服务。

为了保护模型字段,您可以使用不同的解决方案来:

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 模式

另一种方法是使用 存储库模式,这会给小项目带来复杂性。

但结果是:

  • 更精简的控制器和模型
  • 在存储库中移动查询逻辑
  • 使查询更具可重用性和解耦性

对于使用此设计模式的项目,此控件可以移至存储库。