phplaravelsentinel

Laravel 6 perform role based routing


I have a route group with different routes. I want to have different role levels access without changing the URL of the application.

For example I want to have /admin as the route and then I want to allow or disallow users based on their roles. Basically, I want every user to be able to see the same page but with different menu options(I know how to do this) but also secure the links from direct access.

Is there a nice way to achieve that without the need of using different middlewares seperately on each route? Since there doesn't seem to be a way to retrieve the $request variable inside the web.php file but only inside a controller. I'm using the sentinel package for auth.

Some sample code of my web.php:

Route::group(
['prefix' => 'admin', 'middleware' => 'customer', 'as' => 'admin.'],
function () {
    // Ad list
    Route::get('getMyAnnonsList', 'Admin\BackEndController@getMyAdList')->name('getMyAdList');       
    }
);

Great answer by @lagbox. This is what I did in the end. Very elegant.

web.php:

Route::group(['prefix' => 'admin', 'as' => 'admin.'], function () {
Route::middleware('admin:admin,user')->group(function(){
            Route::get('getMyAnnonsList', 'Admin\BackEndController@getMyAdList')->name('getMyAdList'); 
        });
});

middleware:

public function handle($request, Closure $next, ...$roles)
{      
    if (!Sentinel::check()) 
        return redirect('admin/signin')->with('info', 'You must be logged in!');
     
    foreach($roles as $role)        
        if($role == Sentinel::getUser()->roles[0]->slug)
            return $next($request);        
   
    return redirect()->back();  
}

Solution

  • I had already answered something like this before, should be working the same still.

    You can create a middleware that can be applied to your group. In that middleware it is asking the route itself for the specific roles to check.

    How to assign two middleware to the same group of routes. Laravel

    Example of middleware:

    class CheckMiddleware
    {
        public function handle($request, Closure $next)
        {
            $roles = $request->route()->getAction('roles', []);
    
            foreach ((array) $roles as $role) {
                // if the user has this role, let them pass through
                if (...) {
                    return $next($request);
                }
            }
    
            // user is not one of the matching 'roles'
            return redirect('/');
        }
    }
    

    Example route definition:

    Route::middleware('rolescheck')->group(function () {
        Route::get('something', ['uses' => 'SomeController@method', 'roles' => [...]])->name(...);
    });
    

    You can apply this arbitrary data at the group level, the individual route level or both, as all routes are individually registered; groups just allow for cascading of configuration.

    You could also have this middleware take parameters, and just merge them with the arbitrary roles, then it is a dual purpose middleware:

    public function handle($request, $next, ...$roles)
    {
        $roles = array_merge($roles, $request->route()->getAction('roles', []));
        ...
    }
    
    Route::middleware('rolescheck:admin,staff')->group(...);