透過 AuthManager 取得 SessionGuard 實例,接著在 Authenticate Middleware 會呼叫 check()
方法驗證。
if ($this->auth->guard($guard)->check()) { return $this->auth->shouldUse($guard); }
|
SessionGuard 的 check()
方法如下:
public function check() { return ! is_null($this->user()); }
|
只要呼叫 user()
的結果不是 null,即是驗證成功。從介面上來看,它應該會回傳 Authenticatable 或是 null:
public function user() { if ($this->loggedOut) { return; }
if (! is_null($this->user)) { return $this->user; }
$id = $this->session->get($this->getName());
if (! is_null($id) && $this->user = $this->provider->retrieveById($id)) { $this->fireAuthenticatedEvent($this->user); }
$recaller = $this->recaller();
if (is_null($this->user) && ! is_null($recaller)) { $this->user = $this->userFromRecaller($recaller);
if ($this->user) { $this->updateSession($this->user->getAuthIdentifier());
$this->fireLoginEvent($this->user, true); } }
return $this->user; }
|
第一次進網站時,沒有 session 也沒有 cookie,因此最後回傳的會是 null,check()
方法將會回傳 false。
那反過來說,何時會回傳 true 呢?session 能取得 id 是一種可能,我們可以從使用 session 屬性方法來查,關鍵更新 session 的方法是 updateSession()
:
protected function updateSession($id) { $this->session->put($this->getName(), $id);
$this->session->migrate(true); }
|
這個方法除了在上面 recaller 的行為也有看到之外,還有 login()
,這也是 StatefulGuard 的介面:
public function login(AuthenticatableContract $user, $remember = false) { $this->updateSession($user->getAuthIdentifier());
if ($remember) { $this->ensureRememberTokenIsSet($user);
$this->queueRecallerCookie($user); }
$this->fireLoginEvent($user, $remember);
$this->setUser($user); }
|
仔細想想,user 不可能丟一個物件進來登入,因此這個 login 方法,應該有被另一個處理 user 輸入的方法使用到,是 attempt()
方法:
public function attempt(array $credentials = [], $remember = false) { $this->fireAttemptEvent($credentials, $remember);
$this->lastAttempted = $user = $this->provider->retrieveByCredentials($credentials);
if ($this->hasValidCredentials($user, $credentials)) { $this->login($user, $remember);
return true; }
$this->fireFailedEvent($user, $credentials);
return false; }
|
基本上使用帳密,透過 attempt()
,即可完成登入流程。若再往上一層級追程式碼的話,就會到 Controller 了,先暫時打住。
回頭看一下 middleware 的 $this->auth->shouldUse($guard)
:
public function shouldUse($name) { $name = $name ?: $this->getDefaultDriver();
$this->setDefaultDriver($name);
$this->userResolver = function ($name = null) { return $this->guard($name)->user(); }; }
|
昨天有提到 middleware 可以傳入多個 guard 驗證。因驗證 user 這件事,對 PHP 的生命週期來說,會是全域唯一的設定;這個方法則是用來設定目前全域唯一要用哪一個 guard。
接著,有登入,也要有登出。來看一下如何登出。
剛剛有看到有一個屬性 loggedOut
是在代表是否執行過登出的 flag。反查了一下,找到 logout()
方法正是在設定這個屬性為 true:
public function logout() { $user = $this->user();
$this->clearUserDataFromStorage();
if (! is_null($this->user)) { $this->cycleRememberToken($user); }
if (isset($this->events)) { $this->events->dispatch(new Events\Logout($this->name, $user)); }
$this->user = null;
$this->loggedOut = true; }
|
跟 login()
不一樣的是,它不依賴任何參數,可以直接在 Controller 呼叫它即可。
到此,簡單的 Authenticate 流程都說明完了。知道這些資訊後,就能使用 Auth 套件實作登入登出了,明天再來談如何客製化登入登出。