分析 Auth(1)
Auth 在 Laravel 開放的 Illuminate 套件包裡(Support 除外),可能是前三名複雜的。
註一:Support 除外的原因是,它比較像是 helper,類別大部分都能獨立運作,如 Facade。
註二:前三名:Database
、Auth
、Queue
之前幾天在分析元件時,都是很容易知道如何開始,因為都有進入點(entry point)。無論是從初始化實例開始或是實際 Laravel 如何使用這個元件,都是有辦法找出開始分析的路徑。但 Auth,但類別本身較複雜,加上沒有使用過 Auth 套件,所以一開始也不知道該如何下手。
這時還有一種方法:看文件。文件通常會用容易理解的方法,讓開發者可以快速了解元件會有哪些角色,以及它們如何互動。從文件去了解套件如何開始分析,是有幫助的。
Authentication
文件裡可以大致知道 Auth 提供兩種類型:Authentication 和 Authorization,今天就先從 Authentication 開始。
裡面有提到的關鍵角色是 Guard 與 Providers。Guard 處理驗證,而 Providers 是提供資料讓 Guard 驗證。相關的 UML 圖如下:
@startuml
interface Illuminate\Contracts\Auth\Authenticatable
interface Illuminate\Contracts\Auth\Factory
interface Illuminate\Contracts\Auth\Guard
interface Illuminate\Contracts\Auth\StatefulGuard
interface Illuminate\Contracts\Auth\UserProvider
class DatabaseUserProvider
class EloquentUserProvider
class GenericUser
class RequestGuard
class SessionGuard
class TokenGuard
class AuthManager
Illuminate\Contracts\Auth\Factory <|.. AuthManager
Illuminate\Contracts\Auth\Factory -> Illuminate\Contracts\Auth\Guard
Illuminate\Contracts\Auth\Factory --> Illuminate\Contracts\Auth\StatefulGuard
Illuminate\Contracts\Auth\Guard <|-- Illuminate\Contracts\Auth\StatefulGuard
Illuminate\Contracts\Auth\Guard o- Illuminate\Contracts\Auth\Authenticatable
Illuminate\Contracts\Auth\Guard <|.. RequestGuard
Illuminate\Contracts\Auth\Guard <|.. TokenGuard
Illuminate\Contracts\Auth\StatefulGuard <|.. SessionGuard
Illuminate\Contracts\Auth\Authenticatable <- Illuminate\Contracts\Auth\UserProvider
Illuminate\Contracts\Auth\Authenticatable <|.. GenericUser
Illuminate\Contracts\Auth\UserProvider <|.. DatabaseUserProvider
Illuminate\Contracts\Auth\UserProvider <|.. EloquentUserProvider
@enduml
從圖可以知道,UserProvider 是建構 Authenticatable 的角色;Factory 是負責建構 Guard;而 Authenticatable 則是提供給 Guard 做驗證用。
Service provider
Auth 套件主要的 service provider 是 AuthServiceProvider:
$this->app->singleton('auth', function ($app) { |
另外,因為已經知道 Facade 的用法了,裡面有一個 Auth Facade 是對應到 Container 綁定的 auth
,也就是 AuthManager。
Authenticate Middleware
知道類別如何綁定後,再來了解它如何被使用。Authenticate Middleware 會檢查使用者是否有驗證,從 handle()
與 authenticate()
可以大概知道需要呼叫哪些參數
// 額外參數使用 ...,代表 guards 是可以設定很多筆的 |
來看 guard()
是如何取得 driver 的,其實跟 SessionManger 或 LogManager 都非常像:
public function guard($name = null) |
resolve()
原始碼:
protected function resolve($name) |
web 的 driver 是 session,對應的方法是 createSessionDriver()
:
public function createSessionDriver($name, $config) |
這裡的寫法其實是有點奇怪的。
$guard
很明確使用new SessionGuard()
建構,該實例會有什麼方法,是可以預期的,因此下面 set 的相關方法,使用method_exists()
判斷就顯得多餘。
經過上面的過程,guard()
就能取得 SessionGuard 實例了。
今天休息一下,明天再繼續看這個 guard 是如何檢查的。