Mick79's avatar
Level 5

Role Middleware in Laravel 11

Evening all!

doing my first project in L11. Previously this would have worked:

Route::get('/approvals', 'App\Http\Controllers\ListingController@show')->middleware('role:super-admin');

EDIT: Using Spatie/Permissions of course

However now I'm getting an error

"Target class [role] does not exist."

I've googled around and asked various GPTs but can't get anywhere.

Please help :-)

0 likes
5 replies
LaryAI's avatar
Level 58

To solve the issue with the role middleware in Laravel 11, you need to ensure that the middleware is properly registered and implemented. Here’s a step-by-step guide to help you set up role-based middleware in Laravel 11:

  1. Create the Middleware: First, create a middleware that will handle the role checking. You can do this using the Artisan command:

    php artisan make:middleware RoleMiddleware
    
  2. Implement the Middleware: Open the newly created middleware file located at app/Http/Middleware/RoleMiddleware.php and implement the logic to check the user's role.

    <?php
    
    namespace App\Http\Middleware;
    
    use Closure;
    use Illuminate\Http\Request;
    use Illuminate\Support\Facades\Auth;
    
    class RoleMiddleware
    {
        /**
         * Handle an incoming request.
         *
         * @param  \Illuminate\Http\Request  $request
         * @param  \Closure  $next
         * @param  string  $role
         * @return mixed
         */
        public function handle(Request $request, Closure $next, $role)
        {
            if (!Auth::check() || Auth::user()->role !== $role) {
                // Optionally, you can redirect to a specific page or return a 403 response
                abort(403, 'Unauthorized action.');
            }
    
            return $next($request);
        }
    }
    
  3. Register the Middleware: Next, you need to register the middleware in your app/Http/Kernel.php file. Add it to the $routeMiddleware array:

    protected $routeMiddleware = [
        // Other middleware
        'role' => \App\Http\Middleware\RoleMiddleware::class,
    ];
    
  4. Apply the Middleware to Routes: Now you can apply the middleware to your routes. Update your route definition to use the role middleware:

    use App\Http\Controllers\ListingController;
    
    Route::get('/approvals', [ListingController::class, 'show'])->middleware('role:super-admin');
    
  5. Ensure User Model Has Role Attribute: Make sure your User model has a role attribute. This could be a column in your users table. For example:

    // In your User model (app/Models/User.php)
    class User extends Authenticatable
    {
        // Other model properties and methods
    
        public function getRoleAttribute()
        {
            return $this->attributes['role'];
        }
    }
    
  6. Database Migration: If you don't already have a role column in your users table, you need to add it. Create a migration to add the role column:

    php artisan make:migration add_role_to_users_table --table=users
    

    Then, update the migration file:

    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('role')->after('email')->default('user');
        });
    }
    
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('role');
        });
    }
    

    Run the migration:

    php artisan migrate
    

By following these steps, you should be able to implement and use role-based middleware in your Laravel 11 application without encountering the "Target class [role] does not exist." error.

Mick79's avatar
Level 5

@LaryAI So you can see old Larry here has got it wildly wrong like all the other GPTs I spoke to. L11 no longer has kernel.php. Tried doing stuff with app.php but no joy.

I guess the main thrust of the question is that in L10 the spatie permission package let you do this out of the box. Has that functionality gone?

jlrdw's avatar
jlrdw
Best Answer
Level 75

@Mick79 I added to bootstrap/app:

<?php

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;
use Illuminate\Support\Facades\Route;

return Application::configure(basePath: dirname(__DIR__))
                ->withRouting(
                        web: __DIR__ . '/../routes/web.php',
                        commands: __DIR__ . '/../routes/console.php',
                        using: function () {
                            Route::middleware('web')
                            ->namespace('App\Http\Controllers')
                            ->group(base_path('routes/web.php'));
                        },
                        health: '/up',
                )
                ->withMiddleware(function (Middleware $middleware) {
                    $middleware->group('web', [
                        \Illuminate\Cookie\Middleware\EncryptCookies::class,
                        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
                        \Illuminate\Session\Middleware\StartSession::class,
                        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
                        \Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class,
                        \Illuminate\Routing\Middleware\SubstituteBindings::class,
                        \Illuminate\Session\Middleware\AuthenticateSession::class,
                    ]);
                })
                ->withExceptions(function (Exceptions $exceptions) {
                    //
                })->create();

https://laravel.com/docs/11.x/middleware#manually-managing-laravels-default-middleware-groups

2 likes
JenuelDev-31676163's avatar

it seems that according to laravel docs, you have to do it this way. By directly using the class. I am actually trying to learn how aliases work in the app.php

->middleware(EnsureUserHasRole::class.':editor,publisher')
JenuelDev-31676163's avatar

I was able to achieve this by adding the class as aliases in the middle ware like so in the app.php.

and then I can do this, in my routes.

// only analyst, admin, super_admin
Route::middleware('role:analyst,super_admin,admin')->group(function () {
        Route::get('/samples', function () {
            return Inertia::render('Analyst/SamplesPage');
        })->name('test_requests.samples');
    });

1 like

Please or to participate in this conversation.