Search code examples
laravellaravel-11

Laravel 11 Policy implementation


I am new to Laravel and am struggling to implement a simple Policy :)

Just for testing I did ->

/app/Policies/ReleasePolicy.php:

<?php

namespace App\Policies;

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

class ReleasePolicy
{
    public function edit(): bool
    {
        return false;
    }
}

routes/web.php:

<?php

use App\Models\Release;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\ReleaseController;

Route::resource('/release', ReleaseController::class);

app/http/controllers/ReleaseController.php:

<?php

namespace App\Http\Controllers;

use App\Models\Release;
use Illuminate\Http\Request;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Response;
use Illuminate\View\View;
use App\Http\Requests\ReleaseStoreRequest;
use App\Http\Requests\ReleaseUpdateRequest;

class ReleaseController extends Controller
{
    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Release $release): View
    {
        return view('pages.release.edit', compact('release'));
    }
}

When I go to http://localhost:8000/release/56/edit , it still opens, I expected 403. What am I doing wrong?

I assume the policy is not registered/discovered, but why not? The laravel/docs says:

By default, Laravel automatically discover policies as long as the model and policy follow standard Laravel naming conventions. Specifically, the policies must be in a Policies directory at or above the directory that contains your models.

And that's exactly what I did but I think the policy is still not discovered...

I tried to manually register the policy in app/Providers/AppServiceProvider.php

<?php

namespace App\Providers;

use App\Models\Release;
use App\Policies\ReleasePolicy;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\User;

class AppServiceProvider extends ServiceProvider
{
  /**
   * Register any application services.
   */
  public function register(): void
  {
    //
  }

  /**
   * Bootstrap any application services.
   */
  public function boot(): void
  {
    Gate::policy(Release::class, ReleasePolicy::class);

  }
}

Nothing changed. http://localhost:8000/release/56/edit doesnt show 403


Solution

  • Policies do not guard the controller methods but the actions on models. In docs https://laravel.com/docs/11.x/authorization#policy-methods, we can see there are some methods which are auto-discoverable by Laravel:

    viewAny, view, create, update, delete, restore, and forceDelete

    In your case, you will need to explicitly check for policy in your edit method, as described in docs: https://laravel.com/docs/11.x/authorization#authorizing-or-throwing-exceptions

        public function edit(Release $release): View
        {
            Gate::authorize('edit', $release);
            return view('pages.release.edit', compact('release'));
        }
    

    Or, I suggest that you use the standard "update" policy method instead of custom "edit":

    class ReleasePolicy
    {
        /**
         * Determine if the given release can be updated by the user.
         */
        public function update(User $user, Release $release): bool
        {
            return false;
            //or some rule...;
        }
    }
    

    And use "update" in contoller: Gate::authorize('update', $release);