一般 Lumen 開發者在剛開始處理身份驗證時,除了用關鍵字餵 Google,最常就是跑去翻官網的 Authentication 文件,然後就會像我一樣,一臉期待地進來,又滿頭霧水地離開。如果沒有 Laravel 經驗而直接接觸 Lumen 的開發者,這份文件真的省略到讓人毫無頭緒。
在開始詳細說明整套身份驗證架構前,我先概略解釋 Authentication 這短短一頁到底在講什麼。
Authentication Service Provider
現在是 DI(Dependency Injection)模式普及的年代,使用服務前要先註冊已經是多數 PHP 開發者的反射動作。然而大部分人照著官方 Authentication 文件註冊完 AuthServiceProvider 後,往下文一看就茫然了,這段語意不明的 code 是從哪冒出來的?
$this->app['auth']->viaRequest('api', function ($request) {
// Return User or null...
});
每個字好像都看得懂,又好像看得不太懂;是的我們知道它是寫在 AuthServiceProvider boot function 中,當服務啟動時運作的一段程式碼,但具體來說是在做什麼?
先等等…不要急,讓我們把視角拉遠,巨大的疑惑放在一邊;整個官方 Authentication 文件在描述的流程,如果用白話文來講大概就是:
- 在系統中註冊一個 身份驗證的服務。
- 當服務啟動時,建立一個 針對連線請求做檢查的守門員。
- 在檢查連線請求的過程中,如果要辨識使用者,可以建立一個 回傳用的使用者物件。
- 在驗證的中介層(auth middleware)當中,呼叫已經建立好的 守門員 進行身份檢查。
現在,我暫時透過簡單的 Q&A 形式回答常見的疑惑;完整的細節和流程留在後續說明。
Authentication 文件 Q&A
viaRequest 函式從哪來的?是指要檢查連線請求嗎?
是也不是。從程式註釋當中來看的話,viaRequest 這個函式的意思比起 via Request,更像是 via RequestGuard,透過 請求守門員 RequestGuard 來處理連線請求。viaRequest 在被呼叫時,會 註冊 一段用來建立 RequestGuard 的函式;真正的 RequestGuard 物件則要等到該 Guard 第一次被解析時才會實例化(這點會在後續文章詳述)。
viaRequest('api', …) 當中的 api 是…?
這個 api 和你在寫的 API 其實沒有直接關聯,它是可以自訂的 auth driver 的索引鍵值,理論上你可以替換成任何字,但要記得在 config/auth.php 做對應的修改。
viaRequest(…, callback) 後面的 callback 是…?
這裡的 callback 是用來 回傳使用者物件 的回呼函式,在官方文件此一架構中,回傳的使用者物件一共有兩個用途:
- 讓 RequestGuard 判斷連線進來的是 使用者 或 訪客(回傳 null 會被判斷為 guest)。
- 當使用者執行
$request->user()時,呼叫此一函式取得 使用者物件。
app['auth'] 又是哪來的?
如你所知,ServiceProvider 裡的 $this->app 就是 Lumen Application 物件本身,而 app['auth'] 是一個 在存取時會自動被產生出來 的 AuthManager 物件,除非你提前存取過了 app['auth'],不然這裡應該是初次實例化的地方,你可以在這段 code 的前後用 isset($this->app['auth']) 試看看。
所以 $this->app['auth']->viaRequest('api', callback) 這整段的意義是?
簡單來說,就是當 AuthServiceProvider 啟動時,會透過自動建立的 AuthManager 物件,註冊一個 RequestGuard 的 auth driver,然後指派一個用來 判斷並取得使用者物件 的回呼函式給它。
真正執行的身份驗證的程式段到底在哪?
以官方 Authentication 文件的架構來說共有兩個地方。其一是 Authenticate Middleware 的 handle 函式內:
if ($this->auth->guard($guard)->guest()) {
return response('Unauthorized.', 401);
}
這裡呼叫了 Guard(預設的 api Guard)來判斷連線身份是否為訪客,如是,則拒絕授權。
其二是 AuthServiceProvider 的 boot 函式內:
$this->app['auth']->viaRequest('api', function ($request) {
// Return User or null...
});
這裡定義的 回傳使用者物件 callback 如果傳回了 null,guard($guard)->guest() 就會為 true — 被視為是 guest 而拒絕授權;相反的若傳回了使用者,就可以安然通過。
結語
如果這篇文章有幫助到你瞭解官方 Authentication 文件,小弟我覺得十分榮幸;但倘若還是無法解開你的疑惑,沒關係,後續我會盡可能完整詳細地拆解整套身份驗證運作機制,希望到時能再帶給你另一番想法。


