Laravel中Model :: find($ id)如何安全?

I have an app where I create entries based on who is signed in. If I use the find($id) method it returns json response. The function is like this:

public function edit($id)
    {
        $chore = Chore::find($id);
        return response()->json($chore);
    }

Now if I where to edit the id value I might be able to access other user's data which isn't secure at all. So I added and extra column user_id that checks who is signed in:

public function edit($id)
    {
        $chore = Chore::find($id)
        ->where('user_id', Auth::id());
        return response()->json($chore);
    }

But of course laravel can't make it easy so it doesn't work. Adding ->get() returns an array instead of a json response. First of all how is find($id) ever secure in any app that uses authentication and secondly how do I add another condition under the find($id) clause? I need data returned in JSON otherwise I will need to rewrite all my front-end which isn't ideal at this point.

我也尝试过:

 public function edit($id)
    {
        $chore = Chore::where('id', $id)
        ->where('user_id', Auth::id());
        return response()->json($chore);
    }

但没有运气

评论
  • 观世音菩萨
    观世音菩萨 回复

    If Chore is in a one-to-one relationship with your User model, then you can create a relationship in your User.php model.

    public function chore() {
        return $this->hasOne(Chore::class);
    }
    

    Then in your controller, you could simply call auth()->user()->chore.

    The Eloquent's find() method finds only one record by the primary key. If you use additional validation it's perfectly safe. You could use route model binding to simplify the code.

    web.php

    Route::get('/chore/{chore}/', 'ChoreController@edit');
    

    然后在您的控制器中

    public function edit(Chore $chore)
    {
       if (! $chore->user_id === auth()->id()) {
         // throw error or redirect, or whetever
       }
    
       return response()->json($chore);
    }    
    

    To simplify the controller a little bit more, you could create a form request and inject it into controller's method as a regular request. (https://laravel.com/docs/7.x/validation#authorizing-form-requests)

    然后,您可以将验证移到您的表单请求中。它看起来应该像这样:

        public function authorize() {
            return $this->route('chore')->user_id === $this->user()->id
        }
    
  • 请勿打扰
    请勿打扰 回复

    You just need to call the where method before the find method

    $chore = Chore::where('user_id', Auth::id())
        ->find($id);
    

    或者,如果您已经在用户模型上正确设置了关系

    // In User.php
    public function chores()
    {
        return $this->hasMany(Chore::class, 'user_id', 'id');
    }
    

    那你也可以

    $chore = Auth::user()->chores()->find($id);
    

    尽管这似乎是多余的工作,但它更加方便和易于维护。