【问题标题】:Validate that exposed primary/foreign keys in a form are intact验证表单中暴露的主键/外键是否完整
【发布时间】:2017-11-13 23:01:17
【问题描述】:

我有一个调查表。每个问题都有 3-4 个预定义答案作为单选按钮。单选按钮的值是数据库中答案的主键。

由于所有问题的所有答案都存储在一个表中,如果用户增加值,ID 可能仍然是有效的外键,但它不属于该问题。

确保单选按钮的值不被操纵的最佳做法是什么?

【问题讨论】:

    标签: php mysql laravel laravel-5


    【解决方案1】:

    在您的控制器中,您可以执行以下操作:

    # Get the ids of the answers that are valid for that question
    $validAnswerIds = $Question->answers->pluck('id')->toArray();
    
    # Validate that the answer given is in there
    $rules = ['answer' => Rule::in( $validAnswerIds ) ];
    $request->validate( $rules );
    

    【讨论】:

      【解决方案2】:

      作为David has already mentioned,您需要验证您的业务逻辑。

      最“laravelish”的方式,如you mentioned,是在您的请求类中执行验证,并在需要时开发额外的验证器扩展。像Erin has mentioned 那样用验证逻辑乱扔你的控制器根本不是一个好习惯;它虽然有效。

      我假设您有两个独立的模型:QuestionAnswer。此外,它们之间的完整 1-N 关系设置为一个问题可以有多个答案并且每个答案都属于一个问题:

      class Question extends Model
      {
          public function answers()
          {
              return $this->hasMany(Answer::class);
          }
      }
      
      class Answer extends Model
      {
          public function question()
          {
              return $this->belongsTo(Question::class);
          }
      }
      

      假设你也有一个SurveyController

      class SurveyController extends Controller
      {
          public function store(CreateSurveyRequest $request)
          {
              // Request is validated by now and you can be sure that the 
              // answer belongs to the question. Go on and create/store 
              // the Survey entity.
          }
      }
      

      以及进行实际数据验证的请求类:

      class CreateSurveyRequest extends FormRequest
      {
          public function rules()
          {
              // Assuming the request contains `answer_id` and `question_id` fields:
      
              return [
                  'answer_id' => 'exists:answers,id,question_id,' . request('question_id'),
                  // e.g. 
                  // 8 => 'exists:answers,id,question_id,10'
                  // Which loosly translates to "answer ID 8 should belong to question ID 10"
              ];
          }
      }
      

      这样的exists 规则定义确保答案记录在questions 表上有一个外键,因此它是问题的有效答案。

      关键是 Laravel 的 exists 规则 supports additional conditions。有趣的是,提交提案的人与您在这里的需求完全相同。

      【讨论】:

      • 非常详细的回答,谢谢。我已经设法用Custom Rule Objects 解决了我的问题。我认为这样我的代码更清洁和可重用。顺便说一句,我不知道 Laravel 的存在规则支持附加条件。这很有趣@sepehr
      • 当然,@ArashMoosapour。是的,使用规则类或验证器扩展是实现自定义验证的主要方法。您的案例可能是belongs cutom 规则的良好候选者。但是,我个人更喜欢坚持通用核心功能,并尽可能避免增加复杂性。
      【解决方案3】:

      确保单选按钮的值未被操纵

      你不能,这是错误的方法。 总是假设客户端信息可以被操纵。

      相反,验证向服务器发出的请求的业务逻辑。当您的服务器端代码收到一组提交的问题和答案时,请根据您拥有的数据验证提交的数据是否有效。

      这可以通过首先查询数据库、执行验证逻辑然后保存数据来完成。可以通过创建存储过程或其他一些数据库端逻辑来确保数据有效,然后只与数据库交互一次。等等。无论哪种方式,都由您来定义和验证系统中规定的业务规则。

      【讨论】:

      • 感谢您的回复,我使用触发器来验证省份是否属于选定的国家或被操纵。实际上我想知道最好的解决方案是什么?在数据库端进行还是在 php 中保留所有验证?哪一项对性能的影响较小?或者也许有这种方法的 laravelish 方式?
      • 业务逻辑验证肯定会发生在您的应用程序代码中。考虑这样一个微不足道的任务对性能的影响绝对是过早优化和自行车棚效应的一个案例。对此的“laravelish”方法是简单地检查QuestionAnswer 模型之间是否存在关系。如果您需要更多详细信息,请考虑使用代码示例更新您的问题,包括您目前所做的工作、您拥有哪些模型以及您的控制器代码是什么样的。
      • @ArashMoosapour:我并不完全熟悉 Laravel 本身的模式和实践,但总的来说,我更倾向于将这样的逻辑放在应用程序代码中。现在,“应用程序”和“数据存储”之间的边界可以(并且经常)发生显着变化,具体取决于系统的整体架构。在某些系统中,“数据存储”脚手架推入应用程序的 DAL,而在其他系统中,“应用程序逻辑”推入 RDBMS。每个系统都是不同的,并且出于不同的原因做事。
      猜你喜欢
      • 1970-01-01
      • 2010-12-15
      • 1970-01-01
      • 2011-05-18
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-06
      相关资源
      最近更新 更多