Search code examples
phplaravelmodelcontrollerpolicy

Laravel 10.4: Problem with policy. User Users should only edit their own posts


I Newbie and am trying to learn Laravel, and I am doing some exercises for Laravel's main functions. I have created a Dashboard where users can add their own posts, however I have noticed that when I open the page to edit the post and change the post ID in the URL, the page opens to edit another user's post. In this case, I would like the 403 page to be displayed. I have followed the instructions on the Laravel website (https://laravel.com/docs/10.x/authorization#writing-policies) to set a policy, but with these instructions I get the 403 page in every post-edit, even in those where I am the owner. users are related to the Posts in the DB via the user_id column. Who can help me?

postpolicy.php

use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;

    public function view(User $user, Post $post): bool
    {
        return $user->id == $post->user_id;
    }

PostController.php

use Illuminate\Http\Request;
use App\Models\Post;
use App\Models\User;
use DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;

class PostController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }


          public function edit(Request $request, Post $post, User $user,  $id)
      {


    $this->authorize('view', $user->post);
    $posts = DB::select('select * from posts where id = ?',[$id]);
     return view('post-edit', ['posts'=>$posts, 'user' => $request->user(),]);
    }
   
}

Models --> Post.php

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use App\Policies\PostPolicy;

class Post extends Model
{
    protected static function boot()
        {
        parent::boot();

        static::creating(function ($post) {
            $post->user_id = auth()->user()->id;
        });
        } }

Route.php

Route::get('post-edit/{id}/edit', [App\Http\Controllers\PostController::class, 'edit'])->name('post.show');
 Route::put('post-edit/{id}', [App\Http\Controllers\PostController::class, 'update'])->name('post.edit');

Solution

  • There are some things wrong in your codes. It should be:

    public function edit(Request $request, $id)
    {
       $post = Post::findOrFail($id);
       $this->authorize('view', $post);
       return view('post-edit', compact('post'));
    }
    

    If you use Implicit Binding https://laravel.com/docs/10.x/routing#implicit-binding like below:

    Route::get('post-edit/{post}/edit', [App\Http\Controllers\PostController::class, 'edit'])->name('post.show');
    

    You can do:

    //The name of $post parameter is the same to the segment {post} 
    public function edit(Request $request, Post $post)
    {
       $this->authorize('view', $post);
       return view('post-edit', compact('post'));
    }