When creating custom Blade views for displaying them to the users when a HTTP error occurs, I cannot access authentication or session variables inside. I'm aware that this happens because the standard "web" middleware does not apply to custom error pages, but I'm not sure if this is intentional. In comparison, the middleware that is applied on every request is also applied on custom pages.
If the behavior is intentional: Is there any way to apply middleware to the error pages, but not calling it on every request?
views/errors/
Auth::check();
)http://stackoverflow.com/questions/41517012/laravel-5-3-use-auth-middleware-on-custom-error-page
Global middlewares are executed on a 404, but route-based middlewares aren't. That's because a 404 does not match a route, so there's no knowledge about which middlewares should execute. You would probably need to modify your exception handler to call the relevant middlewares (at least EncryptCookies and StartSession) when needed.
@sisve Thanks for the reply! Yes, I forgot to mention that global middleware is executed indeed. I've linked my question on StackOverflow which relates to the same topic. I've already thought about setting the StartSession
middleware as a global one, but there should be a better solution.
Do you have an approach for modifying the exception handler for this particular case?
Having the same problem. I'll post if I find a solution, if you do please let me know
This is the intended behaviour. You can't expect laravel to guess whether a root mismatch wants sessions, because then 404s on your api would also start sessions.
Well how can we do Auth::check()
in error pages, I'm sure this would be useful for many people?
I've already thought about setting the StartSession middleware as a global one, but there should be a better solution.
That's the perfect solution if you want sessions across your whole application. Wouldn't make sense to not do that actually. :)
Something I do on one of my apps is actually send an ajax request from the error pages in order to query the session. That's how the login button on StyleCI is able to show up on error pages.
Well how can we do Auth::check() in error pages, I'm sure this would be useful for many people?
You can't, but you can do the solution I just posted. :)
Could you give us an example please?
That's the perfect solution if you want sessions across your whole application. Wouldn't make sense to not do that actually. :)
What about API's? we don't want session middleware in them do we?
What about API's? we don't want session middleware in them do we?
Exactly, so you can't have the middleware on 404s, because they might not be web 404s.
Could you give us an example please?
I already posted the example. I'm not going to write your whole app for you I'm afraid. My description leaves it easy to implement yourself.
@GrahamCampbell Thanks for clarifying the problem and providing an example! Just to make sure that my understanding is correct:
Correct?
@manniL correct, There's also another option. This is how I fixed it without jQuery:
I created a custom StartSession
Class in App\Http\Middleware
<?php
namespace App\Http\Middleware;
use \Illuminate\Session\Middleware\StartSession as BaseStartSession;
use \Illuminate\Http\Request;
use Closure;
class StartSession extends BaseStartSession
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if($request->url() == "api/*"){
return $next($request);
}
return parent::handle($request, $next);
}
}
Notice the way it ignores API Routes.
Then I added that to the global middleware in kernal.php
and removed the old startsession from web
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\StartSession::class,
];
Next I created a class called SessionServiceProvider.php
in App\Providers
<?php
namespace App\Providers;
use Illuminate\Session\SessionServiceProvider as BaseSessionServiceProvider;
use App\Http\Middleware\StartSession;
class SessionServiceProvider extends BaseSessionServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerSessionManager();
$this->registerSessionDriver();
$this->app->singleton(StartSession::class);
}
}
Then finally in app.php
replace Illuminate\Session\SessionServiceProvider::class
with App\Providers\SessionServiceProvider::class
I recommend doing composer dump-autoload
and php artisan optimize
in case it doesn't work
@MrMashy I followed the steps you mentioned and also run the last two commands, still can't access the auth() object.
Correct me if I'm wrong, but when you said "app.php" I updated "configapp.php" right?
@cjwotbot Yes correct, I'm not sure sure what the problem might me. Show me how you're accessing the auth object.
I use auth()->user()
when accessing the auth user object. And if I'm testing it with blade, I use @if(auth()->user())
You should be using \Auth::User();
I was told to use auth()
because we use Auth0 for our authentication.
Anyways, I'll retract my earlier statement when I said it wasn't working, apparently it works now. Thanks!
@cjwotbot Ok great, no problem, Glad it helped.
@MrMashy - Does the work on 5.4? I attempted your changes and am still not able to check the guard on a 500.blade.php custom view
@MrMashy - Does the work on 5.4? I attempted your changes and am still not able to check the guard on a 500.blade.php custom view
I am seeing the same thing in 5.4.27 even when I move ALL middleware to global.
Still not working in 5.4 even if i move this middlewares in global middlewares:
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\Session\Middleware\AuthenticateSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
For those looking for an alternative, non-AJAX solution to this; What I did is create a new middleware group for web-rendered errors in the kernel which are then loaded in dynamically upon error rendering.
Implementation details of this can be seen in this commit (Only Handler.php
and Kernel.php
changes are relevant).
@GrahamCampbell what happens when you have custom layouts based on a session parameter? I have a middleware which determines the partner based on the sub-domain partnerx.domain.com and a layout specific to that partner is loaded.
Is there not a way we could load a partner specific error page? I have been including other layout files based on the value of the {{ session('partner')['username'] }} variable but in 404 error pages we cannot have access to the session since I cannot add it to the global middleware without affecting our API layer.
I understand an ajax request works in your case but I do not think that is possible for our use case, is there any other way to inject the middleware into the response once it is determined that the error is a web error and not an api error?
@ssddanbrown will that only work on web requests or will that also work for api requests?
@ssddanbrown I tried to implement this with Laravel 5.3 however it would appear that the method getMiddlewareGroups is not part of the route, any idea how to do this with 5.3?
The @MrMashy's approach solved the issue!
Thank you!
PS: I'm using v5.5
@DominusVilicus the approach solved the issue in Laravel 5.6 with php artisan clear-compiled
command. But still have a problem with geting the route name: href="{{ route('pages.index') }}"
ErrorException (E_ERROR)
Call to a member function getName() on null
I've already thought about setting the StartSession middleware as a global one, but there should be a better solution.
That's the perfect solution if you want sessions across your whole application. Wouldn't make sense to not do that actually. :)
Something I do on one of my apps is actually send an ajax request from the error pages in order to query the session. That's how the login button on StyleCI is able to show up on error pages.
Sending AJAX request on 404 to trigger the session? This is nuts!
If it is still useful to someone, the solution to my problem:
app/Exceptions/Handler.php
public function __construct(
Container $container,
StartSession $startSession,
ShareErrorsFromSession $errorsFromSession
) {
$this->startSession = $startSession;
$this->errorsFromSession = $errorsFromSession;
parent::__construct($container);
}
public function render($request, Exception $e)
{
if (null === $request->getSession()) {
return $this->startSession->handle($request, function($request) use ($e) {
return $this->errorsFromSession->handle($request, function ($request) use ($e) {
return parent::render($request, $e);
});
});
}
return parent::render($request, $e);
}
//=======================
Voc锚 pode ciar uma rota para a sua view de erro 404:
Route::get('/404', function () { return view('404'); });
//=======================
// VA EM: appExceptionsHandler.php = adiciono o IF na function render para redireciona para sua rota de p谩gina n茫o encontrada.
public function render($request, Exception $exception){
//====IF===
if ($exception instanceof
SymfonyComponentHttpKernelExceptionNotFoundHttpException)
{
return redirect(url('/404'));
}
//=======
return parent::render($request, $exception);
}
Most helpful comment
@manniL correct, There's also another option. This is how I fixed it without jQuery:
I created a custom
StartSession
Class inApp\Http\Middleware
Notice the way it ignores API Routes.
Then I added that to the global middleware in
kernal.php
and removed the old startsession fromweb
Next I created a class called
SessionServiceProvider.php
inApp\Providers
Then finally in
app.php
replaceIlluminate\Session\SessionServiceProvider::class
withApp\Providers\SessionServiceProvider::class
I recommend doing
composer dump-autoload
andphp artisan optimize
in case it doesn't work