0

I am writing an app that has a control panel. I would like to keep the control panel's chrome in the 404 and 403 pages provided the user is logged in. However Auth::user() and auth()->id() always return null in app/Exceptions/Handler.php and obviously the blade directives also don't work as expected (user always appears to be logged out)

Having done a bit of research it appears that this is because the StartSession middleware is not loaded. One way to solve the issue seems to be to enable the middleware globally but that would create potential security issues with the API routes.

So my question is how do I add middleware to the Handler.php? Defining a constructor does seem to work. However calling $this->middleware() like in Controllers does not. Perhaps there is some other syntax for loading the middleware

kaan_a
  • 3,503
  • 1
  • 28
  • 52

1 Answers1

1

I figured it out thanks to this thread on github: https://github.com/laravel/framework/issues/17187, particularly ssddanbrown's and DominusVilicus's comments. But mainly [ssddanbrown's commit to Bookstack][1] I only changed one file app/Exceptions/Handler.php

I added

use Illuminate\Http\Request;
use Illuminate\Pipeline\Pipeline;

before the class decleartion. Created the following method:

/**
* Load Session middleware then run the callback closure and return its result 
*
* @param  \Illuminate\Http\Request $request
* @param  \Closure $callback
* @return \Illuminate\Http\Response
*/
protected function loadSessionMiddleware(Request $request, \Closure $callback)
{
    $pipe = new Pipeline($this->container);

    $middleware = [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    ];

    return $pipe->send($request)->through($middleware)->then($callback);
}

And modified the render method as such:

public function render($request, Exception $exception)
{
    if (
        // Only process non API requests' ...
        $request->segment(1) !== 'api' &&
        // ... HTTP exceptions with ...
        $this->isHttpException($exception)
    ) {

        $code = $exception->getStatusCode();
        // ... codes between 400 and 599
        if ($code >= 400 && $code < 600) {

            return $this->loadSessionMiddleware(
                $request,
                function ($request) use ($exception, $code) {

                    // Load error names and descriptions from language files
                    $name = __('http-errors.' . $code . 'n');
                    $desc = __('http-errors.' . $code . 'd');

                    // Display the error page
                    return response()->view(
                        'errors.http',
                        compact('code', 'name', 'desc'),
                        $code
                    );
                }
            );
        }
    }
    return parent::render($request, $exception);

Now after this the @auth and @guest blade directives work as expected in the template.

. .

Note: I use a single view template and language files to render multiple error pages, because I expect to have to localize my project but the contents of your callback function and your conditional might be slightly simpler if you only want to add the middleware to 404 pages. More importantly this part of the code actually doesn't completely fulfill it's mission since not all exceptions that produce HTTP code 400-599 responses are instances of HTTPException, specifically: AuthorizationException and AuthenticationException.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
kaan_a
  • 3,503
  • 1
  • 28
  • 52
  • Thank you for this answer! I was searching everywhere and basically got the same results that you had, until I came across this question. Bless you and have a nice day! – AhmCho Jan 17 '23 at 07:41