Laravel auth() component not available on error views - php

Framework: Laravel 9.x
I'm attempting to use custom error pages. These are located in the default location: /resources/views/errors/....
These load as expected. However, they extend the base view template. This template uses the auth()->user() functionality to make decisions on visible menus.
The auth()->user() does not work on the error views. Note that it works as expected on other views.
How do I load the authenticated user for these error file views?
Thanks in advance.

Add this at the end of your route file for 404 error. Usually 404 doesn't get the session.
Route::fallback(function () {
return abort(404);
});
All other errors such as 401, 403, 419, 429, 500, 503 these gets the session by default you do not need to do anything for that. Basically 404 means you do not have that route so system kicks user out of the system, in that case kernel does not load with all providers. if provider do not load you will not get session. So for 404 we are telling our system let our user stay but if the page is not available use fallback route.
If you want to test it for each errors you can do something like this.
Create a blank route
Route::get('/blank', fn() => abort(401));
go to 401.blade.php change message to auth()->user()->id.
visit the /blank URL.
If you see your id your session is working.

Related

Laravel 8 Auth middleware protected route failing

I am building my first Laravel app with the Metronic 8 Laravel theme. It uses Breeze for authentication. I changed a couple of things around - created a welcome page for non-logged-in users, and moved the main template that was the index to an auth protected "/dashboard". The problem is that it still tries to load the dashboard Blade template, regardless of authentication, resulting in an error.
Route
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth'])->name('dashboard');
Here's Authenticate, where it should redirect non-authenticated users to the login page.
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
When I'm not logged in and navigate to the dashboard URL, it attempts to load the dashboard Blade template, which calls a menu function that checks the user permissions for menu items. Unfortunately, since there is no user, the application blows up from passing a null value to a method expecting a user array/object.
Any ideas on where to look for the problem? It seems to me that the auth middleware should redirect to the login page before trying to load the Blade template when not logged in.
I would put the middleware at the beginning of the route like this, though I'm sure it's not causing the problem-
Route::middleware(['auth'])->get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
Aside from that, please provide some information on the error itself like what the error is about/what is says..etc...
First of all, make sure you have a login named route defined in your routes/web.php file. It should look something like:
Route::get('/login', '<controller>#<method>')->name('login');
The important bit is ->name('login') so that the Authenticate middleware can correctly identify the route to redirect to. Change <controller>#<method> appropriately to route to the login method of your app.
Wakil's answer is irrelevant and actually opposite of the documentation. Your syntax is correct.
I figured out the issue. Keen Themes put a call to a method to build an array of menu items in the web routes file. That was making the call to the offending code. After I wrapped that in an auth check the error was fixed, and everything works as expected.

Custom 404 error template in twig 2.5 with symfony 4.1

I created customs Twig templates for http error display to keep the site design unified by extending my base layout. (I want to keep my navigation menu and display the error, unlike the regular error messages)
It's working as expected but for the 404.
In the navigation menu of my base layout, I have a lot of is_granted('SOME_ROLES') to display the availables sections of the site depending of user's rights. When a 404 is thrown, the navigation menu is displayed as if the user is disconnected : {% if is_granted("IS_AUTHENTICATED_REMEMBERED") %} being false.
After some searches, I found that the router is executed before the firewall. Since no route is found when a 404 is thrown, the firewall isn't executed and the rights aren't send to the template.
The only workaround I found (source from 2014) is to add at the very bottom of the routes.yaml file this route definition :
pageNotFound:
path: /{path}
defaults:
_controller: App\Exception\PageNotFound::pageNotFound
Since every other routes hasn't match, this one should be the not found.
The controller :
<?php
namespace App\Exception;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
class PageNotFound
{
public function pageNotFound()
{
return (new NotFoundHttpException());
}
}
Because a controller is executed, the firewall is executed and the 404 error page is shown as I expected (hooray !).
My question is : Is there any proper way to fix that issue instead of that workaround?
We had a similar issue.
We wanted to have access to an authentication token in error pages.
In the scenario where part of the website is behind a firewall, say example.com/supersecretarea/, we wanted than unauthorized users get a 403 error code when accessing any url behind example.com/supersecretarea/, even in the event that the page doesn't exist. Symfony's behavior does not allow that and checks for a 404 (either because there is no route or because the route has parameter which didn't resolve, like example.com/supersecretarea/user/198 when the is no user 198).
What we ended up doing was to override the default router in Symfony (Symfony\Bundle\FrameworkBundle\Routing\Router) to modify its behavior:
public function matchRequest(Request $request): array
{
try {
return parent::matchRequest($request);
} catch (ResourceNotFoundException $e) {
// Ignore this next line for now
// $this->targetPathSavingStatus->disableSaveTargetPath();
return [
'_controller' => 'App\Controller\CatchAllController::catchAll',
'_route' => 'catch_all'
];
}
}
CatchAllController simply renders the 404 error page:
public function catchAll(): Response
{
return new Response(
$this->templating->render('bundles/TwigBundle/Exception/error404.html.twig'),
Response::HTTP_NOT_FOUND
);
}
What happens is that during the regular process of Symfony's router, if something should trigger a 404 error, we catch that exception within the matchRequest function. This function is supposed to return information about which controller action to run to render the page, so that's what we do: we tell the router that we want to render a 404 page (with a 404 code). All the security is handled in between matchRequest returning and catchAll being called, so firewalls get to trigger 403 errors, we have an authentication token, etc.
There is at least one functional issue to this approach (that we managed to fix for now). Symfony has an optional system that remembers the last page you tried to load, so that if you get redirected to the login page and successfully log in, you'll be redirected to that page you were trying to load initially. When the firewall throws an exception, this occurs:
// Symfony\Component\Security\Http\Firewall\ExceptionListener
protected function setTargetPath(Request $request)
{
// session isn't required when using HTTP basic authentication mechanism for example
if ($request->hasSession() && $request->isMethodSafe(false) && !$request->isXmlHttpRequest()) {
$this->saveTargetPath($request->getSession(), $this->providerKey, $request->getUri());
}
}
But now that we allow non-existing pages to trigger firewall redirections to the login page (say, example.com/registered_users_only/* redirects to the loading page, and an unauthenticated user clicks on example.com/registered_users_only/page_that_does_not_exist), we absolutely don't want to save that non-existing page as the new "TargetPath" to redirect to after a successful login, otherwise the user will see a seemingly random 404 error. We decided to extend the exception listener's setTargetPath, and defined a service that toggles whether a target path should be saved by the exception listener or not.
// Our extended ExceptionListener
protected function setTargetPath(Request $request): void
{
if ($this->targetPathSavingStatus->shouldSave()) {
parent::setTargetPath($request);
}
}
That's the purpose of the commented $this->targetPathSavingStatus->disableSaveTargetPath(); line from above: to turn the default-on status of whether to save target path on firewall exceptions to off when there's a 404 (the targetPathSavingStatus variables here point to a very simple service used only to store that piece of information).
This part of the solution is not very satisfactory. I'd like to find something better. It does seem to do the job for now though.
Of course if you have always_use_default_target_path to true, then there is no need for this particular fix.
EDIT:
To make Symfony use my versions of the Router and Exception listener, I added the following code in the process() method of Kernel.php:
public function process(ContainerBuilder $container)
{
// Use our own CatchAll router rather than the default one
$definition = $container->findDefinition('router.default');
$definition->setClass(CatchAllRouter::class);
// register the service that we use to alter the targetPath saving mechanic
$definition->addMethodCall('setTargetPathSavingStatus', [new Reference('App\Routing\TargetPathSavingStatus')]);
// Use our own ExceptionListener so that we can tell it not to use saveTargetPath
// after the CatchAll router intercepts a 404
$definition = $container->findDefinition('security.exception_listener');
$definition->setClass(FirewallExceptionListener::class);
// register the service that we use to alter the targetPath saving mechanic
$definition->addMethodCall('setTargetPathSavingStatus', [new Reference('App\Routing\TargetPathSavingStatus')]);
// ...
}

Laravel returning a blank page only on certain routes

I'm having an issue where a route is returning a blank page. I am using Homestead as my dev environment and I'm unsure how to debug.
The /storage/logs/laravel ... isn't returning any exceptions when I visit the white page.
web.php (where it's failing):
Route::get('/clinic/register', 'ClinicController#register');
Controller.php:
public function register()
{
return view('clinic.register', ['specialisms' => Specialism::pluck('specialism', 'id')]);
}
Yet when I visit /clinic/register I am shown a blank white page. How can I see why it's failing? Surely a white page will return an exception somewhere?
As you have not provided your entire route setup. This answer is my best guess. See if it helps.
Your issue hint at improper route setup. If you have created a clinic resource then clinic/register route should precede it.
// clinic/register route should come first
Route::get('clinic/register','ClinicController#register');
// followed by rest of the routes which resource will create
Route::resource('clinic','ClinicController');
The reason behind getting a blank pages is because Route::resource will create some route with wildcards.
For e.g. clinic/{clinic} which will map to show method on controller. So when you make a get request to clinic/register it will be mapped to this show method instead of your register method.
One possibility for not getting any errors is your show method does not have any code yet. Hence, a blank response.
To summarize: Order in which you register your routes matters

Laravel 5 Error Pages

I'm having problems creating error pages for my L5 app. I created a controller called BaseController which has all my CSS/JS and every other controller I have extends from it. How does one create an error 404 page which also extends BaseController?
Simply creating a view in views/errors/404.blade.php does not work since no styles are loaded. I'm using Twigbridge which is really useful when working with views.
Am assuming when you say controller has CSS/JS it means that your setting up layout using controllers.
Please note that this works for routes that you clearly define in your routes file and their respective controllers extend the Base.
For Error Pages they are not handle by your controllers. The error handlers are responsible for rendering their views and won't extend any layout. Hence you need to complete define it in your error view.
This should get you off on the right foot. Just use your standard extends syntax to extend your "default" layout.
Do a search for App::error, you will find the right spot.
App::error(function(Exception $exception, $code)
{
$params = array();
$request = Request::create('cms/noroute', 'GET', $params);
return Route::dispatch($request)->getContent();
});
There is no need to handle the errors within a controller or even the assets files. Imagine you have an error from laravel (missing a config file) so you will have the error before event the code could reach a controller. The same case goes for 404. If you do not have that route available, there is no need to let user reach a controller, this is handled by Exception Handler.
A good resource to learn more is Laravel documentation and this blog post

Resetting the View in Zend Action Helper

I am checking an ACL in the pre-dispatch method of an ACL Action Helper. If the action is-allowed, the controller/action should continue as per normal. (No problems there). If it's NOT allowed, however, I would like to:
leave the requsted URI in the browser
skip executing the requested action method
generate an 'access denied' message
At first I thought I would just call _forward() in the Action Helper, but I can't since it's a protected method. The View Renderer Action Helper says that gotoSimple is like _forward, however it still performs the full http redirect (and thus changes the URI in the browser).
I could try calling setScriptPath() on View, then Render(), however this would not prevent the requested controller/action from firing. I think there's probably a straightforward answer to this, but it's beyond my level of experience!
Any assistance appreciated!
This is most easily solved by simply throwing a Zend_Controller_Action_Exception, preferably with code 401 (Unauthorized).
This will be caught by the error handler plugin and forwarded to the Error controller.
You can then check for this error code and handle it appropriately. This is in my error controller
if ($errors->exception->getCode() == 401) {
$this->getResponse()->setHttpResponseCode(401);
return $this->_forward('unauthorized');
}
The "unauthorized" action just displays a view but you could do more with it (log an error for example)

Categories