Featured image of post In Route Permission Control, a Paginated List Permission Can Simultaneously Control All List Permissions

In Route Permission Control, a Paginated List Permission Can Simultaneously Control All List Permissions

A Simple and Effective Method for Permission Control

Recently encountered an issue while implementing permission control for API endpoints.
This builds upon our previous permission control method: Using Route-Based Permission Control in Laravel (Applicable Beyond Laravel, as a Conceptual Approach)


We have two route aliases:
Paginated city list: cities.index
Complete city list: cities.index.all

These represent two separate permissions. To ensure users with only the cities.index permission can also access cities.index.all (since both belong to list operations under normal logic), we need to make minor adjustments to our validation logic.

<?php

namespace App\Http\Middleware;

use App\Models\Permission;
use App\Models\User;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

class AdminPermission
{
    /**
     * Process:
     * 1. Get current route name
     * 2. Check if route requires permission
     * 3. Grant access or throw permission exception
     *
     * @param Request $request
     * @param Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        $route = Route::currentRouteName();

        // This route has no name
        if (is_null($route)) {
            return $next($request);
        }

        // Handle routes ending with .all
        if (ends_with($route, '.all')) {
            $route = substr($route, 0, -4);
        }

        // Check if route requires permission
        // Consider using cache for performance optimization
        if ($permission = Permission::query()->where('route', $route)->first()) {

            /**
             * @var $user User
             */
            $user = $request->user();

            // Verify user permission
            if (! $user->hasPermissionTo($permission)) {
                throw new UnauthorizedHttpException('permission', trans('error_permission.denied'), null, Response::HTTP_FORBIDDEN);
            }
        }

        return $next($request);
    }
}

Key implementation details:

  1. Normalizes route names ending with .all by removing the suffix
  2. Maintains existing permission verification logic
  3. Allows inherited permissions between paginated and complete list views

This approach ensures users with list permissions automatically get access to both paginated and complete list variations without duplicate permission assignments.