How to apply middleware for Permission in Route Dynamically in Laravel (Spatie Permission)?

Viewed 46

In my Laravel application, I have 5 pages. This is just an example.

  • About
  • Service
  • TermsAndCondition
  • PrivacyPolicy
  • Contact

For display those page i have create one controller called PageController.

PageController

public function index($page)
{
    return view('page', compact('page));
}

web.php

Route::get('/{page}', [PageController::class, 'index'])->where('page' => ['about|service|termscondition|privacypolicy|contact']);

For manage permission, I am using Spatie Permission package.

I have some permission. e.g

  • about.view
  • service.view
  • termscondition.view
  • privacypolicy.view
  • contact.view

User only can view those pages after login if they have permission (This concept is for demo purpose only).

If I have individual route for every page then I can apply middleware('can:about.view') like this way.

But in this case, where i am using one route for every pages dynamically, so how can I apply middleware for permission?

1 Answers

Make entity Page (if you don't have a model) like this:

class Page implements UrlRoutable
{
    private string $page;

    public function __construct(string $page)
    {
        $this->page = $page;
    }

    public function getPage(): string
    {
        return $this->page;
    }


    public function getRouteKey()
    {
        return $this->getPage();
    }

    public function getRouteKeyName()
    {
        return 'page';
    }

    public function resolveRouteBinding($value)
    {
        return new self($value);
    }
}

Hint: Implementing UrlRoutable contract allow us to use this class in routing like model.

Make a PagePolicy for Page like other policies

class PagePolicy
{
    use HandlesAuthorization;

    public function view(User $user, Page $page)
    {
        $permission = 'view.' . $page->getName();
        return $user->can($permission);
    }
    
    //other methods
}

Register policy in AuthServiceProvider:

    protected $policies = [
        Page::class => PagePolicy::class
    ];

And than, in controller, you can just use gate functional:

    public function index(Page $page)
    {
        $this->authorize('view', $page);
        //or
        Gate::check('view', $page);
        return view('page', compact('page'));
    }

Or use this in middleware:

Route::get('/{page}', [PageController::class, 'index'])->where('page' => ['about|service|termscondition|privacypolicy|contact'])->middleware('can:view');
Related