Accessing Auth in Exceptions\Handler.php - php

I'm trying to access the Auth class from within the render method of the App\Exceptions\Handler class (app/Exceptions/Handler.php) to determine if the User is currently logged in, using the Auth::check() method.
This worked fine in 5.1, but I've upgraded to 5.2 and it no longer works.
To debug this, I've been printing Auth::user() to the logs (which returns NULL), then returning a redirect() to another view.
Then from the view/controller the redirect goes to, printing the same Auth::user() to the logs, which works as expected and returns the logged in user.
So it seems there's no problem accessing the Auth class or the user() method from within the Exceptions\Handler class, it's just that it returns NULL for some reason, whereas other parts of the app return the User..
Thanks for any info on this!

This happens because StartSession middleware is inside $middlewareGroups (the application's route middleware groups), so you don't have access to the authenticated user because the middlewares that initialize your session starts later in the lifecycle than the ExceptionHandler.
In app\Kernel.php file, move this line:
\Illuminate\Session\Middleware\StartSession::class,
from $middlewareGroups to the global stack $middleware. These middleware are run during every request to your application so, after this, Auth::user() will works.
WARNING: With this solution you will not be able to use the cookie session driver. Works well with file and others.
UPDATE:
If you still need to use StartSession inside global stack $middleware and also you need cookie session driver, you must move three middlewares from $middlewareGroup to $middleware in the next order:
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class

After some research, it seems the 404 errors are the only culprits. If it's a 500 error, Auth::user() works. So, in my routes.php file, I added this at the bottom
Route::any('{page}', 'ErrorController#Error404')->where('page', '(.*)');
to catch any unhandled endpoints. In that ErrorController#Error404 method, I can access the Auth class. So whatever logic you have in your App\Exceptions\Handler, you can duplicate it in the ErrorController#Error404 method. (Or better: extract it to some other entity that can be referenced in both places.)

Related

Laravel Route::current() returns null

I am trying to use the current route in middleware in Laravel 5.7 using the following line of code:
$route = Route::current();
But I get a null value for $route. Any ideas?
The route couldn't be available yet because the router hasn't been yet called. That's depends on what middlewares are called before your middleware.
I think that, in a before middleware, you can try with: $route = $request->path(); just to be sure and not depending on the Router being booted or not.
You just want to change where your middleware is registered in app/Http/Kernel.php if you need access to the Route facade.
I'm betting that your middleware is in the protected $middleware array. It should be in one of your $middlewareGroups usually web or api. Or if you need it for a specific route you can add it to the $routeMiddleware array.
For example, I wanted to access Route from within my HandleInertiaRequests middleware so I had to move to $middlewareGroups like shown in this screenshot:

Laravel 5.6 - How to authenticate API using sessions for same folder SPA?

I have a React SPA in the same Laravel project. The login/signup/logout and all other js views are in the js folder and use axios api calls for all POST/GET requests. I want to use the default Laravel session based web authentication for the embedded SPA, since it's in the same project folder and it will be the only javascript client accessing it. This api does not need to be open to the public, just for this react app, and it's an SPA for the speed and good user experience instead of full page reloads.
I've tried using Passport before, and for over a month, I still can't get it to work as intended. I do not want to deal with tokens, access tokens, refresh tokens, revoking tokens, CSRF, etc. Just the out of the box simple Laravel session based auth that works so easily on web, but want it to work on my react app. The only blade file is the index.blade.php which includes the react app.js
Any idea how we can accomplish this?
UPDATE 1:
After implementing #ceejayoz's suggestion:
You have to add the various Session/Cookie middlewares in
app/Http/Kernel.php (stuff like
\Illuminate\Session\Middleware\StartSession::class) to the API routes.
I added to $middlewareGroups.api to match the web middleware in app/Http/Kernel.php:
'api' => [
'throttle:60,1',
'bindings',
// Newly added middleware to match web middleware
\App\Http\Middleware\EncryptCookies::class
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
I realized there are two issues that occurred:
In the sessions table, even if not logged in, when loading app home page (or any page), multiple sessions are inserted into the sessions table. Shouldn't a new single session be inserted into this table only after user login?
After user log in, when refreshing the page manually in the browser and a call is made to a protected route, I get a 401 Unauthenticated which points me to this method in Illuminate/Auth/GuardHelpers.php:
public function authenticate() {
if (! is_null($user = $this->user())) {
return $user;
}
throw new AuthenticationException; // throws this 401 exception on logged in page refresh when fetching data from private route
}
Some additional notes:
In config/auth.php I updated the guards.api.driver to session instead of token.
In routes/api.php I have the protected routes wrapped in auth middleware like this: Route::group(['middleware' => 'auth'], function() { PRIVATE ROUTES HERE }
In config/session.php I have 'domain' => '.mydomain.com'
I am sending back these headers with each axios api request like this:
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
let token = document.head.querySelector('meta[name="csrf-token"]');
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
Any idea how we can fix these 2 issues?
Looks like your session was not persistent.
Check if you changed any values in config/session.php that might create problems.
You can check default sesion config values here
From the comments, #Wonka solved his problem by changing
'same_site' => 'strict'
to
'same_site' => null
It's doable (and I've done the same myself for some apps).
By default, the routes in routes/api.php don't have sessions available, but you can add the various Session/Cookie middlewares in app/Http/Kernel.php (stuff like \Illuminate\Session\Middleware\StartSession::class) to the API routes.
You can, as #ljubadr suggested, also put the API routes right in routes/web.php instead, although that'd probably mean you'd need to make other changes (like removing CSRF protection from the web routes).

Laravel REST API - infinite loop

I am building a REST user-microservice using Laravel 5.5 + Passport.
I am using the standard Passport::routes(), but I have had to modify the Auth::routes in order to make them return JSON responses, and to make them work with Passport.
I have added the following lines to my routes/web.php file:
Route::group(['middleware' => 'auth:api'], function () {
$this->post('logout', 'Auth\LoginController#logout')->name('logout');
});
This allows me to POST https://myapi/logout
If I make the call with the header "Authorization => Bearer TOKEN", I get a successful logout response.
If I provide no header at all, I get a "not authenticated" message (which is good)
However, if I provide the header with a revoked token, I get a recursive deadloop of the function: Illuminate\Auth\RequestGuard->user() (it keeps calling itself recursively until stack-overflow)
This is all done in the auth:api middleware, my logout code is not reached, but my LoginController constructor is called. Constructor code:
public function __construct(Application $app)
{
$this->apiConsumer = $app->make('apiconsumer');
$this->middleware('guest')
->except('logout');
}
I'm struggling to understand if it's my code causing this issue, or some combination of Laravel + passport + auth.
My first thought was that the auth:api middleware fails to authenticate the user, and as a result redirects the user to /home, where for some reason it's triggered again, recursively. But if that was the case, why would it work correctly with no header?
My current thinking is that the token in question does exist in the database, but Laravel is failing to figure out that it's revoked.
Any suggestions appreciated,
I found an answer (if not the answer) after a lot of research. It appears this is a Laravel bug (https://github.com/laravel/passport/issues/440). The solution is to add OAuthServerException to the $dontReport array in app/Exceptions/Handler.php:
class Handler extends ExceptionHandler
{
protected $dontReport = [
...
\League\OAuth2\Server\Exception\OAuthServerException::class,
];
}
This will avoid trying to log user information, thereby avoid the deadloop.
I have faced this in localhost. in my case, I have used xampp server and facing this issue
after creating a virtual host like "testlarave.test" then solve the error

Laravel package session variable not saving with ajax call

I'm building a package called under-construction. When this package is activated in a config
file the site will be underconstruction only people with the right code can access the
application.
https://github.com/larsjanssen6/underconstruction
The problem that I have right now:
When the code is entered I make an ajax call that hit's this controller method (called check):
https://github.com/larsjanssen6/underconstruction/blob/master/src/Controllers/CodeController.php
If the code is correct a session variable is being set:
session(['can_visit' => true]);
Then in my vue.js code I redirect to /. And it will hit my middleware again. Here I check if a session called can_visit exists.
return session()->has('can_visit');
https://github.com/larsjanssen6/underconstruction/blob/master/src/UnderConstruction.php
But the session variable can_visit is always gone! How is that possible?
Thanks for your time.
You're not loading the session middleware, so session is not started and no values are persisted.
As was mentioned in the comments, even though your protected routes (/) are within the web middleware (read session), your service provider's routes (/under/construction, /under/check) are not (no write session).
The simple fix is to add the session, or even better, the whole web middleware.
$routeConfig = [
'namespace' => 'LarsJanssen\UnderConstruction\Controllers',
'prefix' => 'under',
'middleware' => [
'web', // add this
// DebugbarEnabled::class, // leaving this dead code behind despite vcs
],
];
However, you might quickly run into trouble with infinite redirect loops if a user adds your middleware to their web middleware group. So I would add a check of some sort to make sure you're not on one of the existing underconstruction routes.
public function handle($request, Closure $next)
{
// check this isn't one of our routes
// too bad router hasn't loaded named routes at this stage in pipeline yet :(
// let's hope it doesn't conflict with user's routes
if ($request->is('under/*')) {
return $next($request);
}
if (! $this->config['enabled']) {
return $next($request);
}
if (!$this->hasAccess($request)) {
return new RedirectResponse('/under/construction');
}
return $next($request);
}
And ultimately guessing from the context of this project, I'd expect most people would want to stick this in the global middleware. However, you're going to run into the same session-hasn't-started-yet issues because that doesn't run in the global middleware. So there's more to chew on. Happy coding!

Access Session Variable in Laravel Custom Error Pages

I am trying to create a custom error page in Laravel 5.3. I wanted the retrieve some variable stored in the Session like Session::get("username"), however what I get is an empty variable.
How am I suppose to get any Session variable in a custom error page in Laravel or is it not possible?
As Laravel did not find the route, you did not pass through the middleware \Illuminate\Session\Middleware\StartSession (which is by default in web middleware group), so your session is not started.
To have your session initialized, move \Illuminate\Session\Middleware\StartSession::class, from web to $middleware in Kernel.php:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Session\Middleware\StartSession::class,
],
Middlewares in $midleware are always run so your session will be initialized, even if the route is not found.

Categories