skip to Main Content

I’m facing an issue in Laravel related to the middleware after I updated to from Laravel 7 to 9 and Backpack from 4 to 5.

I should get redirected to the login page (example.com/admin/login) when I try to access a route I’m not allowed to without being logged in (like example.com/admin/contacts).

Instead I get an error Call to a member function can() on null which indicates, that my admin middleware CheckPasswordStatus is executed before the auth-middleware.

This is my middleware declaration in Kernel.php:

protected $middlewareGroups = [
        'web' => [
            AppHttpMiddlewareEncryptCookies::class,
            IlluminateCookieMiddlewareAddQueuedCookiesToResponse::class,
            IlluminateSessionMiddlewareStartSession::class,
            IlluminateViewMiddlewareShareErrorsFromSession::class,
            AppHttpMiddlewareVerifyCsrfToken::class,
            IlluminateRoutingMiddlewareSubstituteBindings::class,
        ],
        'admin' => [
            CheckPasswordStatus::class,
        ],
        'api' => [
            'throttle:5000,10',
            IlluminateRoutingMiddlewareSubstituteBindings::class,
        ],
    ];

    protected $routeMiddleware = [
        'auth' => AppHttpMiddlewareAuthenticate::class,
        'auth.basic' => IlluminateAuthMiddlewareAuthenticateWithBasicAuth::class,
        'auth.basic.source' => AppHttpMiddlewareAuthenticateWithBasicAuthForSources::class,
        'cache.headers' => IlluminateHttpMiddlewareSetCacheHeaders::class,
        'can' => IlluminateAuthMiddlewareAuthorize::class,
        'guest' => AppHttpMiddlewareRedirectIfAuthenticated::class,
        'password.confirm' => IlluminateAuthMiddlewareRequirePassword::class,
        'signed' => AppHttpMiddlewareValidateSignature::class,
        'throttle' => IlluminateRoutingMiddlewareThrottleRequests::class,
        'verified' => IlluminateAuthMiddlewareEnsureEmailIsVerified::class,
    ];

I use it in my route declaration in routes/backpack/custom.php as follows:

Route::prefix(config('backpack.base.route_prefix', 'admin'))->middleware([backpack_middleware(), config('backpack.base.web_middleware', 'web')])->group(function () { // custom admin routes
    Route::crud('contact', ContactCrudController::class);
    Route::crud('conflicts', IncomingImportConflictCrudController::class);
    Route::patch('contacts/{id}/advertising-rejection', [ContactCrudController::class, 'advertisingRejection'])->name('contact.advertising_rejection');
    Route::post('conflicts/{id}/new', [IncomingImportConflictCrudController::class, 'creatNewContact'])->name('new-contact');
    Route::get('conflicts/{id}/compare/{compareId}', [IncomingImportConflictCrudController::class, 'compare']);
    });

In my config/backpack/base.php is the 'middleware_key' => 'admin'.

The middleware CheckPasswordStatus simply checks if a user’s password has expired and if so, it redirects them to a password reset page:

public function handle($request, Closure $next)
    {
        if ($user = $request->user()) {
            if ($user->passwordIsExpired()) {
                return redirect()->route('password.reset.manually');
            }
        }

        return $next($request);
    }

When I use something as the middleware_key (which isn’t defined in my middleware groups), it works as expected, leading to a redirection to the login screen. Shouldn’t this throw another error? Maybe there is some default behavior.

When I set the middleware_key back to admin but comment out the admin middleware in Kernel.php, everything works fine. (except the CheckPasswordStatus::class-middleware)

When I use web as the middleware_key, I get the same error and no redirect.

I tried the two solutions from
Laravel Middleware Error – Call to a member function isBasic() on null
but if I use the authenticated method in 'CheckPasswordStatus::class' the error says, CheckPasswordStatus middleware not callable

If i use the Auth::check() as condition in the 'CheckPasswordStatus::class' I got an empty page instead of a redirect.

2

Answers


  1. I think you should be fine by adding your middleware to middleware_class
    https://github.com/Laravel-Backpack/CRUD/blob/1b67f8efdbaa48842e0d31995068b44b8fc5c66d/src/config/backpack/base.php#L266

    You can get the authenticated user with: backpack_user() or backpack_auth()->user() or Auth::guard('admin')->user()(if admin is your guard name).

    Cheers

    Login or Signup to reply.
  2. You can try explicitly setting the middleware priority, if you are relying on a specific order of middleware execution. Add this in your Kernel.php:

    protected $middlewarePriority = [
        IlluminateFoundationHttpMiddlewareHandlePrecognitiveRequests::class,
        IlluminateCookieMiddlewareEncryptCookies::class,
        IlluminateSessionMiddlewareStartSession::class,
        IlluminateViewMiddlewareShareErrorsFromSession::class,
        IlluminateContractsAuthMiddlewareAuthenticatesRequests::class,
        IlluminateRoutingMiddlewareThrottleRequests::class,
        IlluminateRoutingMiddlewareThrottleRequestsWithRedis::class,
        IlluminateContractsSessionMiddlewareAuthenticatesSessions::class,
        IlluminateRoutingMiddlewareSubstituteBindings::class,
        AppHttpMiddlewareAuthenticate::class,
        IlluminateAuthMiddlewareAuthorize::class,
        CheckPasswordStatus::class
    ];
    
    

    This should ensure CheckPasswordStatus runs after the authenticate and authorise middleware

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search