最近的一個PHP項目,上一個項目是採用ThinkPHP來弄的,因為很早就聽説過Laravel的大名,所以進了Laravel的官網,意外發現了Lumen,正好我項目是提供API的,所以選擇了Lumen,因為是Laravel的精簡版,看了幾天的Laravel文檔,也總結出了自己的一些經驗,不權威:
1、Larave的核心是服務容器,服務容器的主要功能是依賴注入
2、Laravel的各部分功能以組件形式提供,需要什麼注入什麼
下面進入正題JWT認證,感謝學習 Lumen 用户認證 (二) —— 使用 jwt-auth 插件這篇文章對我的幫助。
如何做用户認證?
根據Laravel文檔描述,Laravel提供用户認證的接口,他的核心是看守器(Guard)和提供器(Provider),看守器定義怎麼認證用户,提供器定義怎麼檢索用户。
首先創建項目lumen new jwt-demo,然後進入jwt-demo目錄,執行composer require tymon/jwt-auth:1.0.0-rc.2,在項目根目錄下創建config文件夾,並將vender/laravel中的auth.php拷貝到config目錄下,auth.php文件內容如下:
然後修改boostrap/app.php文件,添加如下配置
修改路由文件routers/web.php
一定要使用jwt.auth中間件,然後在Controllers目錄下新建App/AuthController.php文件,文件內容如下:
修改app/Exceptions/Handler.php文件
然後瀏覽器訪問域名/auth/home,結果如下:
那麼現在從源碼看一下401是怎麼來的?
![]()
這裏定義了這個路由,要經過
jwt.auth這個中間件,下一步這個中間件在哪裏定義的呢,
可以看到在
LumenServiceProvider中有$this->app->routeMiddleware($this->middlewareAlias)這麼一句,
可以看到在這裏是定義了一個名為
jwt.auth的路由中間件,對應Tymon\JWTAuth\Http\Middleware\Authenticate這個類,看一下這個類的實現
可以看到是通過
$this->authenticate這個方法進行驗證的,那麼現在看下這個方法的實現
可以看到這裏有兩個方法,
checkForToken用來驗證是否存在token,如果不存在則拋出異常,如果存在則進入$this->auth->parseToken()->authenticate()用來驗證token是否合法,怎麼驗證token是否存在這裏不做討論,我們來看下他是怎麼驗證token是否合法的,跟蹤代碼發現執行的事JWTAuth類的下面方法
可以看到首先從payload中獲得id值,然後通過id檢索用户,如果檢索成功,返回false,token不合法,否則返回檢索到的用户,token合法,那麼跟蹤一下檢索用户的代碼,最終進入的是
JWTGuard類的如下方法
$this->provider就是我們在config/auth.php中配置的
eloquent,對應的類是
EloquentUserProvider,我們看下它的retrieveById方法,實現如下
這裏就已經在從數據庫中查找用户,在實際研發中對於數據庫的查找我們可能有自己的邏輯,那麼我們只能去實現我們自己的Provider然後去替換掉
JWTGuard中的Provider,那麼這一步該怎麼做呢?
在bootstrap/app.php有這麼一句$app->register(Tymon\JWTAuth\Providers\LumenServiceProvider::class);,我們可以看下LumenServiceProvider的源碼,
可以看到有這麼一個方法,我們可以去看下他的實現,
可以看到這裏傳入了Provider,那麼我們看一下AuthManager的createUserProvider方法
程序會先去讀取Provider的配置信息,也就是auth.php中的
這麼一部分,然後判斷
customProviderCreators中是否存在對應的Guard的驅動,如果存在則根據驅動創建用户自定義Provider,否則判斷driver是否為datebase或者eloquent,如果也不成立則拋出異常,否則創建DatebaseProvider或者EloquentProvider,那麼根據這麼一段代碼,我們只需要在auth.php配置好自己的驅動,然後將我們自己的Provider實現類注入到customProviderCreators去就可以了,那麼怎麼注入呢,在AuthManager中有這麼一個方法
至此如何自定義
Provider就解決了,現在就來實戰一下,自定義的Provider代碼如下,
參照
EloquentUserProvider和DatebaseUserProvider可知需要實現UserProvider接口,為了方便,我就直接繼承DatebaseUserProvider了,重寫了retrieveById方法,默認返回true,首先修改auth.php中的provider的driver為my,然後就是注入MyJWTUserProvider了,在app/Jwt目錄下新建一個MyLumenServiceProvider,代碼如下
最後將
boostrap/app.php中register的LumenServiceProvider改為MyLumenServiceProvider
至此JWT還剩下一個生成用户驗證返回token的過程