場景是這樣的,我用tymon/jwt包做鑒權。jwt是自編碼token,過期前想要強制失效只能將其加入黑名單中,黑名單一般用緩存存儲。
但會有一個問題,若某種意外情況不小心執行了php aritsan cache:clear,那么當前使用的緩存數據庫(配置文件中設置,默認config/database.php->redis->default)會被清空,而tymon/jwt包也是用default數據庫的,故黑名單的token也會被一並清空。
如何在不改第三方包的前提下修改黑名單使用的redis數據庫?這樣token就能獨占一庫,不用和其他緩存數據一起混在當前使用數據庫中,即使php aritsan cache:clear也不會受影響
查看源碼:
Tymon\JWTAuth\Blacklist.php
點進繼續追蹤,發現Storage的實現是Tymon\JWTAuth\Providers\Storage\Illuminate.php的Illuminate類。
Illuminate在構造函數中注入了一個CacheContract,即Illuminate\Contracts\Cache\Repository,這其實就是laravel的Cache緩存類,最后注入的緩存對象使用的就是config/cache/redis中指定的數據庫(已經從第三方包追到框架源碼了,所以我就不繼續追了),我的場景下就是default
如果我們想讓這個包不注入默認的Cache對象,而使用我們指定的Cache對象,我們可以用laravel的服務提供者:https://laravel-china.org/docs/laravel/5.6/providers/1360與服務容器進行上下文綁定:https://laravel-china.org/docs/laravel/5.6/container/1359#contextual-binding
在App\Providers\AppServiceProvider->register()方法中
對Tymon\JWTAuth\Providers\Storage\Illuminate注入的Illuminate\Contracts\Cache\Repository進行注冊(注冊為我們想要的對象):
/** * Register any application services. * * @return void */ public function register() { $this->app->when(Illuminate::class) //use Tymon\JWTAuth\Providers\Storage\Illuminate ->needs(Repository::class) //use Illuminate\Contracts\Cache\Repository ->give(function () { return app('cache')->store('jwt'); }); }
即當Illuminate需要注入Repository時,注入function()閉包內返回的對象,在閉包里用store()方法指定緩存使用的緩存存儲,也就是我們自定義的jwt存儲(config/cache.php):
驅動使用redis,連接的數據庫就是config/database.php->redis中我們自定義的jwt數據庫
這樣,第三方包注入依賴對象的時候,就會使用服務提供者提供的對象進行注入(我的場景里注入的就是專門jwt數據庫的Cache對象),這就是laravel服務容器和服務提供者強大的地方。