Provide your isAdmin() and route code
Auth::user() returns null when app is in production mode
Recently, I've published a new site but I immediately started receiving error messages. On every page request, it says Call to a member function isAdmin() on null. The line of code is the following one:
@if (Auth::user()->isAdmin())
Now the weird thing about this is that my application keeps working normally. I'm logged in, as an administrator, and I can use all the functionalities an admin should be able to use. The Monolog handler takes care of my error messages and pushes them to a Slack channel, where I get these errors. So I get no messages on screen while browsing the site.
But the weird thing is that I don't get these errors anymore when I change APP_ENV=production to APP_ENV=local.
Is there anyone who had this problem before and can help me with this? I've been searching and browsing the web for a couple of days now, but to no avail.
Thx in advance!
isAdmin() function:
public function isAdmin()
{
return (isset($this->admin) && $this->admin);
}
Route code:
Auth::routes();
# Dashboard
Route::group(['middleware' => ['auth']], function() {
Route::get('/', ['as' => 'home', 'uses' => 'HomeController@index']);
});
# Admin backend
Route::group(['middleware' => ['auth', 'isadmin'], 'prefix' => 'admin'], function() {
Route::get('/', ['as' => 'admin.races.index', 'uses' => 'RaceController@adminindex']);
});
I notice now that I also get the error when I'm not logged in and get redirected to /login. This is very strange as I don't include Auth::user() in this view.
@if (Auth::user()->isAdmin()) will cause an error if there is no authenticated user. Use @if(Auth::check()) or @if(!Auth::guest()) to check for that.
Other than that, it sounds like there might be a problem in your middleware or controller code.
Do you get the error on /login or only on /admin/login?
Please post the correspoding controller code.
Edit: If the error happens even after you've logged in, it's likely a session problem. Check to make sure your sessions are being generated properly.
It gets weirder. When I just remove the code where he asks for Auth::user(), I get another error, now saying Undefined variable: errors, and again, only in production mode.
@if ($errors->any())
<div class="Alert Alert--danger Nav Nav--stacked u-marginBmd">
<ul class="Nav-list">
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
@36864 I use the default authentication controller:
<?php
namespace Illuminate\Foundation\Auth;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
trait AuthenticatesUsers
{
use RedirectsUsers, ThrottlesLogins;
/**
* Show the application's login form.
*
* @return \Illuminate\Http\Response
*/
public function showLoginForm()
{
return view('auth.login');
}
/**
* Handle a login request to the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response
*/
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
/**
* Validate the user login request.
*
* @param \Illuminate\Http\Request $request
* @return void
*/
protected function validateLogin(Request $request)
{
$this->validate($request, [
$this->username() => 'required|string',
'password' => 'required|string',
]);
}
/**
* Attempt to log the user into the application.
*
* @param \Illuminate\Http\Request $request
* @return bool
*/
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->has('remember')
);
}
/**
* Get the needed authorization credentials from the request.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
protected function credentials(Request $request)
{
return $request->only($this->username(), 'password');
}
/**
* Send the response after the user was authenticated.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
protected function sendLoginResponse(Request $request)
{
$request->session()->regenerate();
$this->clearLoginAttempts($request);
return $this->authenticated($request, $this->guard()->user())
?: redirect()->intended($this->redirectPath());
}
/**
* The user has been authenticated.
*
* @param \Illuminate\Http\Request $request
* @param mixed $user
* @return mixed
*/
protected function authenticated(Request $request, $user)
{
//
}
/**
* Get the failed login response instance.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\RedirectResponse
*/
protected function sendFailedLoginResponse(Request $request)
{
$errors = [$this->username() => trans('auth.failed')];
if ($request->expectsJson()) {
return response()->json($errors, 422);
}
return redirect()->back()
->withInput($request->only($this->username(), 'remember'))
->withErrors($errors);
}
/**
* Get the login username to be used by the controller.
*
* @return string
*/
public function username()
{
return 'email';
}
/**
* Log the user out of the application.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->invalidate();
return redirect('/');
}
/**
* Get the guard to be used during authentication.
*
* @return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard();
}
}
It gets weirder. When I just remove the code where he asks for Auth::user(), I get another error, now saying Undefined variable: errors, and again, only in production mode.
That's not weird at all, if you're not passing in the $errors variable, and you use it without first checking if it's set.
I think we're getting a little ahead of ourselves here with trying to identify several errors at once, so let's reset.
You said you get the error "on every page request". Is that every page request on the admin route group or does it also happen on the user route group?
If it only happens on the admin route, please post your 'isadmin' middleware.
@36864 It's just peculiar that this suddenly happens, when I've put the application live. But to answer your question: It happens on every request, not only the admin route group. Also on the /login page, where there is no such thing as Auth::user() in the template files.
Can you trace the line that's throwing the exception?
@36864 Yes.
The error:
Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function isAdmin() on null in /home/forge/test.com/storage/framework/views/1cd5117f38a25824cd81d4fca75f1cc37cbf8a99.php:3
The file:
<nav class="Nav Nav--alignRight Nav--user">
<ul class="Nav-list u-sm-flexCol u-sm-flexNoWrap u-sm-flexAlignItemsCenter u-xs-flexCol u-xs-flexNoWrap u-xs-flexAlignItemsCenter">
<?php if(Auth::user()->isAdmin()): ?>
<li class="Nav-item">
<a class="Nav-link" href="<?php echo e(route('admin')); ?>">
<i class="fa fa-cog"></i>
<span class="u-hidden"><?php echo e(trans('users.settings')); ?></span>
</a>
</li>
<?php endif; ?>
<li class="Nav-item">
<a class="Nav-link" href="<?php echo e(route('logout')); ?>" onclick="event.preventDefault(); document.getElementById('Form--logout').submit();">
<i class="fa fa-power-off"></i>
<span class="u-hidden"><?php echo e(trans('users.logout')); ?></span>
</a>
</li>
</ul>
<form class="u-hidden" id="Form--logout" action="<?php echo e(route('logout')); ?>" method="POST">
<?php echo e(csrf_field()); ?>
</form>
</nav>
I'm very confused right now.
Also on the /login page, where there is no such thing as Auth::user() in the template files.
Looks to me like what you just posted is part of your layout, which would also be a part of your login page.
Replace @if(Auth::user()->isAdmin()) with @if(Auth::check() && Auth::user()->isAdmin()) in your layout file.
@36864 I am very grateful. It works. But I still don't get why, actually. And how it's possible that I didn't get this errors on my local dev environment.
Thx!
Only explanation I can come up with right now is some sort of cache voodoo. Maybe you added the admin check to your pages but didn't clear the cache before testing it. Maybe there's something wrong with your logout route which made you think you were logged out when you weren't. If you really want to find out, clear cache on your dev environment, purge sessions, and see if it still works without the new fix.
Please or to participate in this conversation.