Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Ligonsker's avatar

Using permission-checking middleware once instead of many times

I deleted my previous post as I posted it with mistakes. This is the current situation: There are two tables:

  1. List of permission groups:
id | permission_group 
---|------------------
1  |   permission_group_x
2  |   permission_group_y
3  |   permission_group_z
  1. List of users with their assigned groups:
user_id | permission_group_id
--------|---------------------
   97   |          1
   11   |          2
   11   |          3
   53   |          3
   81   |          3
   53   |          1

Then in web.php, each route group is assigned a Middleware that gets a list of all allowed permission groups, and if the current user is in any of these groups (a user can be in more than one group), then he has access. Otherwise you redirect the user to a forbidden page.

But right now because there are hundreds of routes, I am using this Middleware hundreds of times.

Is there any way to convert it to wrap all the routes?

0 likes
9 replies
Sinnbeck's avatar

Or you can wrap all your routes in a route group

1 like
Ligonsker's avatar

@Sinnbeck The problem is, each route group is assigned different permission groups.

So if I have hundreds of these groups:

List of users with their assigned groups:

Route::middleware(['permissions_groups: x, y'])->group(function () {
    Route::get('/orders/{id}', 'show');
    Route::post('/orders', 'store');
});

Route::middleware(['permissions_groups: x, y, z, a'])->group(function () {
    Route::get('/post/{id}', 'show');
    Route::post('/post', 'store');
});

Then I still need to do it individually

Sinnbeck's avatar

@Ligonsker correct. Then you need to do it individually. You can also move it to the controller constructor if you prefer

1 like
Ligonsker's avatar

@Sinnbeck Do you think there's a better way to do it, or "convert" this current method to a single use somehow? At first I was thinking about using the route names somehow to match with the permission groups in the db, but not sure if it adds too much complexity to the point it's better to do it individually, even if it means to do it hundreds of times

Sinnbeck's avatar

@Ligonsker I use groups myself and find it to be the best solution for me. I can very quickly see what routes are in a group.

1 like
Talinon's avatar

@ligonsker

I don't see a huge problem with middleware group wrappers in the route files. But, if you really want to try to eliminate them, there might be some things you could do. As you mentioned, url matching might be one way, but you mentioned they don't currently align.

If all your routes are handled by controllers, maybe you could base the middleware upon the controller. Something like this:

Routes file

Route::get('posts', [PostController::class, 'index']);

Middleware class

const PERMISSION_REGISTRY = [
	'PostController' => 'post-permission',
	'SomeOtherController' => 'some-other-permission',
];

public function handle($request, Closure $next)
{
	$controller = class_basename($request->route()->controller);
	
	$permission = self::PERMISSION_REGISTRY[$controller] ?? null;

	if (!$permission) {
		// redirect.. permission not found. Log / Notify developer
	} else if (! $request->user()->hasPermission($permission)) {
            // Redirect...
        }		
	}

 return $next($request);
	

}

And then just either wrap all your routes in one group, or add it to your RouteServiceProvider so it's applied against all routes.

You'd need to be careful about not duplicating controller names. You could always just use the full namespace to solve that issue. Just remove the class_basename() and add the full namespace to the "registry"

1 like
Ligonsker's avatar

That could work, but in my situation the permission is not per Controller, it's per group of routes :/. Might need to be more specific in that PERMISSION_REGISTRY array. But then again I wonder if it will just make more issues than just individually assigning the correct permissions to each group

Talinon's avatar

@ligonsker If you just want to get rid of the wrapping group functions within your route files, you could just add ->middleware() to each route. You could then remove all the function groups, brackets and a level of indentation.

Route::get('/orders/{id}', OorderController@show')->middleware('permissions_groups: x, y');
Route::post('/orders', 'OrderController@store')->middleware('permissions_groups: x, y');

Route::get('/post/{id}', 'PostController@show')->middleware('permissions_groups: x, y, z, a');
Route::post('/post', 'PostController@store')->middleware('permissions_groups: x, y, z, a');

I think that is your best option. As previously mentioned, you could move it to the controllers, but I'd argue it's probably better to put it on the routes as it's all contained and explicitly defined in one place.

Please or to participate in this conversation.