【问题标题】:Laravel 5 how to validate route parameters?Laravel 5 如何验证路由参数?
【发布时间】:2015-07-26 03:01:01
【问题描述】:

我想验证“表单请求”中的路由参数但不知道怎么做。

下面是代码示例,我正在尝试:

路线

// controller Server
Route::group(['prefix' => 'server'], function(){
    Route::get('checkToken/{token}',['as'=>'checkKey','uses'=> 'ServerController@checkToken']);
});

控制器

namespace App\Http\Controllers;


use App\Http\Controllers\Controller;

use Illuminate\Http\Request;
use App\Http\Requests;


class ServerController extends Controller {
    public function checkToken( \App\Http\Requests\CheckTokenServerRequest $request) // OT: - why I have to set full path to work??
        {   
            $token = Token::where('token', '=', $request->token)->first();      
            $dt = new DateTime; 
            $token->executed_at = $dt->format('m-d-y H:i:s');
            $token->save();

            return response()->json(json_decode($token->json),200);
        }
}

CheckTokenServerRequest

namespace App\Http\Requests;

use App\Http\Requests\Request;

class CheckTokenServerRequest extends Request {

        //autorization

        /**
         * Get the validation rules that apply to the request.
         *
         * @return array
         */
        public function rules()
        {

            return [
                'token' => ['required','exists:Tokens,token,executed_at,null']
            ];
        }

}

但是当我尝试验证一个简单的 URL http://myurl/server/checkToken/222 时,我得到了响应:no " token " parameter set

是否可以在单独的“表单请求”中验证参数,或者我必须在控制器中完成所有操作?

ps。对不起我的英语不好。

【问题讨论】:

  • 您需要只验证路由参数还是与请求参数“混合”?
  • 只有路由参数。。有什么区别吗?谢谢!
  • 你有没有尝试使用中间件。您甚至可以包含多个中间件。因此您可以在组路由中使用。请参考这里laravel.com/docs/5.2/middleware
  • 好问题,我喜欢这个话题。

标签: laravel laravel-5 routes laravel-validation laravel-request


【解决方案1】:

对于 Laravel
方法是覆盖CheckTokenServerRequestall() 方法,如下所示:

public function all() 
{
   $data = parent::all();
   $data['token'] = $this->route('token');
   return $data;
}

编辑
对于 Laravel >= 5.5:
上述解决方案适用于 Laravel 。如果你想在 Laravel 5.5 或更高版本中使用它,你应该使用:

public function all($keys = null) 
{
   $data = parent::all($keys);
   $data['token'] = $this->route('token');
   return $data;
}

改为。

【讨论】:

  • 如果您想坚持在请求类中进行验证,我同意这是解决此问题的唯一方法。小的改进是自动替换所有路由参数:pastebin.com/pjwrPme6.
  • 如果你在函数中添加$all = null参数,它适用于5.5/5.5。
  • 我无法使用您的解决方案。我对您的回答有疑问:stackoverflow.com/questions/52402139/…
【解决方案2】:

重写 Request 对象上的 all() 函数以自动将验证规则应用于 URL 参数

class SetEmailRequest
{

    public function rules()
    {
        return [
            'email'    => 'required|email|max:40',
            'id'       => 'required|integer', // << url parameter
        ];
    }

    public function all()
    {
        $data = parent::all();
        $data['id'] = $this->route('id');

        return $data;
    }

    public function authorize()
    {
        return true;
    }
}

在注入请求后,像这样从控制器正常访问数据:

$setEmailRequest->email // request data
$setEmailRequest->id, // url data

【讨论】:

    【解决方案3】:

    如果您不想指定每个路由参数而只放置所有路由参数,您可以像这样覆盖:

    Laravel :

    public function all()
    {
       return array_merge(parent::all(), $this->route()->parameters());
    }
    

    Laravel 5.5 或更高版本

    public function all($keys = null)
    {
       // Add route parameters to validation data
       return array_merge(parent::all(), $this->route()->parameters());
    }
    

    【讨论】:

    • 如果您使用的是FormRequest,您还可以覆盖validationData 方法,例如protected function validationData() { return $this-&gt;route()-&gt;parameters() + $this-&gt;all(); }
    • 对于 L8,我使用你的缩写版本 $validator = Validator::make(array_merge($request->all(), $request->route()->parameters()), ['country ' => '必填...
    【解决方案4】:

    表单请求验证器用于验证通过 POST 方法发送到服务器的 HTML 表单数据。最好不要将它们用于验证路由参数。路由参数主要用于从数据库中检索数据,因此为了确保您的令牌路由参数正确,请从

    $token = Token::where('token', '=', $request->token)->first();
    

    $token = Token::where('token', '=', $request->input(token))->firstOrFail();
    

    firstOrFail() 是一个非常好的函数,如果用户插入任何无效令牌,它会向您的用户发送 404。

    你得到no " token " parameter set,因为 Laravel 假设你的“token”参数是一个 POST 数据,而在你的情况下它不是。

    如果你坚持验证你的“token”参数,通过表单请求验证器你会减慢你的应用程序,因为你对你的数据库执行两个查询, 一个在这里

    $token = Token::where('token', '=', $request->token)->first();
    

    这里有一个

    return [
                'token' => ['required','exists:Tokens,token,executed_at,null']
            ];
    

    我建议使用 firsOrFail 同时进行验证检索

    【讨论】:

    • 我喜欢你的关心,我同意参数验证不是FormRequest 的真正责任,但这不是很有用吗? Laravel 文档中没有说 FormRequests 应该只用于POST 请求。我的意思是,我们有DELETEPUT 和其他类型的需要数据验证的请求。如果 FormRequest 是将 Controller 逻辑与 Validation 逻辑分开的方法,那就是要走的路。你怎么看待这件事?我想我从这个角度改变了主意。
    【解决方案5】:

    一个 trait 会导致这个验证相对自动化。

    特质

    <?php
    
    namespace App\Http\Requests;
    
    /**
     * Class RouteParameterValidation
     * @package App\Http\Requests
     */
    trait RouteParameterValidation{
    
        /**
         * @var bool
         */
        private $captured_route_vars = false;
    
        /**
         * @return mixed
         */
        public function all(){
            return $this->capture_route_vars(parent::all());
        }
    
        /**
         * @param $inputs
         *
         * @return mixed
         */
        private function capture_route_vars($inputs){
            if($this->captured_route_vars){
                return $inputs;
            }
    
            $inputs += $this->route()->parameters();
            $inputs = self::numbers($inputs);
    
            $this->replace($inputs);
            $this->captured_route_vars = true;
    
            return $inputs;
        }
    
        /**
         * @param $inputs
         *
         * @return mixed
         */
        private static function numbers($inputs){
            foreach($inputs as $k => $input){
                if(is_numeric($input) and !is_infinite($inputs[$k] * 1)){
                    $inputs[$k] *= 1;
                }
            }
    
            return $inputs;
        }
    
    }
    

    用法

    namespace App\Http\Requests;
    
    use Illuminate\Foundation\Http\FormRequest;
    
    class MyCustomRequest extends FormRequest{
        use RouteParameterValidation;
    
        /**
         * Determine if the user is authorized to make this request.
         *
         * @return bool
         */
        public function authorize(){
            return true;
        }
    
        /**
         * Get the validation rules that apply to the request.
         *
         * @return array
         */
        public function rules(){
            return [
                //
                'any_route_param' => 'required'//any rule(s) or custom rule(s)
            ];
        }
    }
    

    【讨论】:

    • 就我个人而言,我认为任何人都不应该为此扩展 FormRequest,如果您明白我的意思,它就不是真正的表单请求。不过,特质的想法仍然很棒..
    • @giovannipds - 你会如何推荐应用这个特征?扩展其他东西,或者从头开始制作请求类?
    • 我没想过,也许只是扩展基本的Request 是要走的路,而不是特质。只是不要将它与FormRequest 混合。当然,您可以将代码基于FormRequest,但不应从那里扩展它。正如我所说,它们是不同关注点的事情。如果稍后某个时间FormRequest 因任何原因更改,它不会影响您自己的Request。当然,这只是我的看法。
    • 在大多数情况下,在php artisan make:request ...吐出的任何类上使用该特征应该没问题
    • 是的……我还在想这该死的东西。我讨厌扩展原始FormRequest 的想法,但这太有用了。你的 trait 与像这样覆盖 validationData 方法有什么不同:protected function validationData() { return $this-&gt;route()-&gt;parameters() + $this-&gt;all(); }
    【解决方案6】:

    对于\App\Http\Requests\CheckTokenServerRequest,您可以在顶部添加use App\Http\Requests\CheckTokenServerRequest;
    如果您通过url 传递token,您可以像使用controller 中的变量一样使用它。

    public function checkToken($token) //same with the name in url
    {
    
        $_token = Token::where('token', '=', $token)->first();      
        $dt = new DateTime; 
        $_token->executed_at = $dt->format('m-d-y H:i:s');
        $_token->save();
    
        return response()->json(json_decode($token->json),200);
    }
    

    【讨论】:

      【解决方案7】:

      您只是缺少标记前的下划线。替换为

      _token

      无论你在哪里检查它与 laravel 生成的表单。

      public function rules()
      {
      
          return [
              '_token' => ['required','exists:Tokens,token,executed_at,null']
          ];
      

      【讨论】:

        【解决方案8】:
        $request->merge(['id' => $id]);
        ...
        $this->validate($request, $rules);
        

        $request->merge(['param' => $this->route('param')]);
        ...
        $this->validate($request, $rules);
        

        【讨论】:

          【解决方案9】:

          FormRequest 有一个方法validationData(),它定义了用于验证的数据。因此,只需在表单请求类中使用路由参数覆盖那个:

              /**
               * Use route parameters for validation
               * @return array
               */
              protected function validationData()
              {
                  return $this->route()->parameters();
              }
          

          【讨论】:

            【解决方案10】:

            或保留大部分all 逻辑并覆盖trait \Illuminate\Http\Concerns\InteractsWithInput 中的input 方法

                 /**
                 * Retrieve an input item from the request.
                 *
                 * @param string|null $key
                 * @param string|array|null $default
                 * @return string|array|null
                 */
                public function input($key = null, $default = null)
                {
                    return data_get(
                        $this->getInputSource()->all() + $this->query->all() + $this->route()->parameters(), $key, $default
                    );
                }
            

            【讨论】:

              猜你喜欢
              • 2015-06-17
              • 2016-04-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-04-13
              • 1970-01-01
              相关资源
              最近更新 更多