Hi guys,
Could you explain me why Auth::check() does query to database?
This method is devoted to check whether the user is logged in. So, as to me, there is no point to query database checking his id or whatever.
What do you think?
It will only do that once, take a look at the code in the Guard class
// If we have already retrieved the user for the current request we can just
// return it back immediately. We do not want to pull the user data every
// request into the method because that would tremendously slow an app.
if (! is_null($this->user)) {
return $this->user;
}
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
$user = null;
if (! is_null($id)) {
$user = $this->provider->retrieveById($id);
}
Only the last if statement here checks in the database. So if Auth::check is already used once and the user is set, there won't be any query ;)
Once per what? I see in query monitor that it does it once… for every GET request.
It doesn’t matter how many times I call Auth::check() in the GET request, there is only call to the mysql like this:
Prepare select * from `ec_user` where `ec_user`.`id` = ? limit 1
Execute select * from `ec_user` where `ec_user`.`id` = '2' limit 1
Close stmt
Quit
$id = $this->session->get($this->getName());
// First we will try to load the user using the identifier in the session if
// one exists. Otherwise we will check for a "remember me" cookie in this
// request, and if one exists, attempt to retrieve the user using that.
$user = null;
if (! is_null($id)) {
$user = $this->provider->retrieveById($id);
}
We check here is the session has a user id. If it has we retrieve the user by it's id. If the session doesn't have a user id we continue to get the from the cookie.
// If the user is null, but we decrypt a "recaller" cookie we can attempt to
// pull the user data on that cookie which serves as a remember cookie on
// the application. Once we have a user we can return it to the caller.
$recaller = $this->getRecaller();
if (is_null($user) && ! is_null($recaller)) {
$user = $this->getUserByRecaller($recaller);
if ($user) {
$this->updateSession($user->getAuthIdentifier());
$this->fireLoginEvent($user, true);
}
}
By default the auth has the user object when the user logs in. It keeps the object in a session till the user logs out or the session expires.
The only time you'll hit the database after log in is if you chain a relationship to the auth object (auth()->hasRole()). Then it will add that to the session upon retrieval.
@bobbybouwmann,
Sorry for my possibly silly questions!
The thing is I’m still a newbie in Laravel, you know. ))
So, when the session you are talking about does expire?
As I see, Auth::check() calls database server every web request but once. Hence this session starts and expires every single request from the browser, doesn’t?
@jekinney
I see that you as think as I do.
However, I do see in mysql log that every get-request like http://localhost:8000/api/auth/check hits the atabase server as I showed before.
Here is my php-code to prove its correctness (I hope, it is):
The thing is, @bobbybouwmann barely confused me with his answers mentioning sessions.
Actually, he said that Auth really does hit a database EVERY request. And I knew that beforehand. I merely don’t understand why is that, for what sake it does it at all.
Actually, you guys explained how Laravel does it once, but no why.
Auth need to retrieve the logged in user for the db in order to work.
Thats all.
If you do $user = Auth::user(); in order to work with the user object, you need to retrieve it from the db isn't it ? So thats all. It is like you were saying, on each page I want to display a post object but why do I have to select the post object everytime.
Stop overthinking small things like this and have fun.
@pmall Sorry for being so restless.
User object should be retrieved when the user isn’t logged in yet or his session is already expired. However, Laravel does it every request which checks authentication, even if the user is perfectly logged in, session is alive and there is no need to retrieve any new information from database.
I expected to get an answer revealing and explaining some kind of security or architectural issues. However you merely answer me “It’s normal, stop think about it ” ;-)
But I can’t stop thinking, because it can lead to performance issues.
I dont understand why do you expect the user info shoudlnt be selected from the database if he is logged in. Where do you expect its data to come from ?
@pmall
Of coutse, it had to be selected from the database at the moment, when the user is logging in.
But it shouldn't be selected again and again when I simply want to check whether the user is still logged in and his session isn't expired.
Laravel does that so you can always access the user object. If you would only check the session this wouldn't work. Unless you would store the complete user object in the session. But that doesn't work either because you might update your name and then the session wouldn't be updated.
Now as a use case take your menu for an example, let's display the username and email (we only use one query here, which is perfectly fine)
@if (Auth::check()) // First query
<li class="username">{{ Auth::user()->username }}</li> // No query
<li class="email">{{ Auth::user()->email }}</li> // No query
@endif
So it is doing it because the user id is stored in session. When Auth::check() the user is retrieved from this id, and it makes sense : let say you ban this user and delete it from the db, he still have its id in session. You have to check if it is a legitimate user otherwise he could still use the website until his session is expiring.
If you don't like this it I dont know what to say. Really it shouldnt matter.
@pmall
Thank you for your response. It makes sense.
And btw, I do have a performance issue with this right now on my developers computer. Yesterday I noticed that Livereload reloads pages seemingly slow and it started hindering. I started looking for the reason and discovered that it was because of slowing down mysql server. It was strange because my template didn’t load anything from the database and the user was already logged in.
Absolutely, in product environment the picture will be different. But I bother anyway.