Home > other >  What causes this failure to use a middleware method in the routes file, in Laravel 8?
What causes this failure to use a middleware method in the routes file, in Laravel 8?

Time:03-02

I am working on a Laravel 8 app with users, roles and permissions. I use Microsoft Azure for user sign-in.

I began by following this tutorial on their website.

I get a list of comma-separated user permissions specific to every user role, from a permissions MySQL table.

I want the current user to have access to certain routes, depending on the permissions they have.

I store the userPermissions variable in a session like this:

public function storeTokens($accessToken, $user, $user_role, $user_permissions) {
    session([
      'accessToken' => $accessToken->getToken(),
      'refreshToken' => $accessToken->getRefreshToken(),
      'tokenExpires' => $accessToken->getExpires(),
      'userName' => $user->getDisplayName(),
      'firstName' => $user->getGivenName(),
      'lastName' => $user->getSurname(),
      'userRole' => $user_role,
      'userPermissions' => $user_permissions,
      'userEmail' => null !== $user->getMail() ? $user->getMail() : $user->getUserPrincipalName(),
      'userTimeZone' => $user->getMailboxSettings()->getTimeZone()
    ]);
}

I have created a new middleware, called CheckUserPermissions:

class CheckUserPermissions
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */

    private $permission;

    // Permissions checker
    public function hasPermissionTo($permission) {
        return in_array($permission, session('userPermissions'));
    }

    public function handle(Request $request, Closure $next)
    {
        // Check user permissions
        if (!$this->hasPermissionTo($this->permission)) {
            return redirect('/')->with('error', 'You do not have permission to access to this section of the application');
        }

        return $next($request);
    }
}

I registered the above middleware in app\Http\Kernel.php:

protected $routeMiddleware = [
    //More middleware
    'checkSignedIn' => \App\Http\Middleware\CheckSignedIn::class,
    'checkUserPermissions' => \App\Http\Middleware\CheckUserPermissions::class,
];

The problem

The problem is that I am unable to use the policy/gate outside the controller (even though the current user does have the permission to view users).

Doing Route::get('/users', [UsersContoller::class, 'index'])->middleware('checkUserPermissions')->hasPermissionTo('view-users') in routes\web.php does not work:

// Dashboard routes
Route::group(['prefix' => 'dashboard', 'middleware' => ['checkSignedIn']], function() {
    Route::get('/', [DashboardContoller::class, 'index'])->name('dashboard');
    Route::get('/users', [UsersContoller::class, 'index'])->middleware('checkUserPermissions')->hasPermissionTo('view-users');
});

It results in a Method Illuminate\Routing\Route::hasPermissionTo does not exist error being displayed in the browser

What am I doing wrong?

CodePudding user response:

You can't access middleware methods in the route definitions. The middleware only runs the handle method so you should write your code with that in mind. Here's how you can solve this:

class CheckUserPermissions
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */

    private $permission;

    // Permissions checker
    public function hasPermissionTo($permission) {
        return in_array($permission, session('userPermissions'));
    }

    public function handle(Request $request, Closure $next, ...$permissions)
    {
        // Check user permissions
        foreach ($permissions as $permission) {
            if (!$this->hasPermissionTo($permission)) { 
               return redirect('/')->with('error', 'You do not have permission to access to this section of the application');
            }
        }

        return $next($request);
    }
}

and use the middleware as:

Route::group(['prefix' => 'dashboard', 'middleware' => ['checkSignedIn']], function() {
    Route::get('/', [DashboardContoller::class, 'index'])->name('dashboard');
    Route::get('/users', [UsersContoller::class, 'index'])->middleware('checkUserPermissions:view-users');
});

Anything after the : in the checkUserPermissions:view-users is sent as an additional argument of the handle method. You can also send multiple ones:

Route::get('/users', [UsersContoller::class, 'index'])->middleware('checkUserPermissions:view-users,see-users,glance-at-users');

each item in the comma separated list is an additional array entry in the $permissions array of the middleware

  • Related