所以我正在開(kāi)發(fā)一個(gè) Laravel 管理應(yīng)用程序,它使用外部 API,我們稱之為 PlatformAPI。平臺(tái)的工作方式是,我的應(yīng)用程序的用戶在平臺(tái)上有一個(gè)帳戶。我的 Laravel 應(yīng)用程序?qū)⒊洚?dāng)管理儀表板,因此用戶可以查看一些從 PlatformAPI 獲取的基本報(bào)告。
我的應(yīng)用程序中的每個(gè)用戶都必須添加他們的客戶端 ID 和客戶端密鑰,他們可以在平臺(tái)中創(chuàng)建這些內(nèi)容。這樣,我的應(yīng)用程序?qū)⒛軌蚴褂糜脩舻膽{據(jù)代表他們向 PlatformAPI 執(zhí)行請(qǐng)求。
我讀過(guò)一些文章和教程,基本介紹了如何為服務(wù)設(shè)置憑據(jù)/令牌并將該服務(wù)綁定到 ServiceProvider,如下所示:
<?php namespace AppServicesPlatformAPI; class Client { protected string $clientId; protected string $clientSecret; public function __construct(string $clientId, string $clientSecret) { $this->clientId = $clientId; $this->clientSecret = $clientSecret; } public function getSales(string $month) { // ... } } <?php use AppServicesPlatformApiClient; class PlatformApiServiceProvider extends ServiceProvider { public function register() { $this->app->singleton(Client::class, function ($app) { return new Client( clientId: config('services.platform-api.client-id'), clientSecret: config('services.platform-api.client-secret'), ); }); } }
這樣,您就不必每次想要使用 PlatformApi 時(shí)都設(shè)置客戶端憑據(jù),我可以像這樣調(diào)用該服務(wù):
<?php namespace AppHttpControllers; use AppServicesPlatformApiClient; class RandomController extends Controller { protected Client $client; public function __construct(Client $client) { $this->client = $client; } public function index() { $this->client->getSales(string $month); } }
但是,由于我需要代表我的應(yīng)用程序的用戶使用他們提供的憑據(jù)(并存儲(chǔ)在我的應(yīng)用程序的數(shù)據(jù)庫(kù)中)向 PlatformApi 執(zhí)行請(qǐng)求,所以我不確定這種相同的方法是否有效,因?yàn)閱卫荒軐?shí)例一次?
此外,為了使用 PlatformApi,我需要使用用戶的憑據(jù)獲取訪問(wèn)令牌。該訪問(wèn)令牌也需要存儲(chǔ)在某個(gè)地方(我想在緩存中)。
我有點(diǎn)不知道如何解決這個(gè)問(wèn)題。任何指示將不勝感激。
我假設(shè)您的所有應(yīng)用程序都將使用此客戶端服務(wù)。如果是這樣,您可以繼續(xù)使用單例設(shè)計(jì)模式(以停止進(jìn)一步的 oauth 請(qǐng)求),但嘗試將邏輯與提供程序的 register 方法分開(kāi)。您可以在調(diào)用返回有效 access_token
的私有方法后實(shí)例化 Client 類(lèi)(如果存在有效令牌,則檢查 DB
/ Cache
expires_in
時(shí)間戳值并返回它,或者向用戶請(qǐng)求一個(gè)新的client
/secret
并返回它)
/** * Register any application services. * * @return void */ public function register(): void { $this->app->singleton(Client::class, function () { return new Client( accessToken: $this->getUserToken()->access_token ); }); } /** * Tries to get the user token from the database. * * @return ClientCredentials */ private function getUserToken(): ClientCredentials { $credentials = ClientCredentials::query() ->latest() ->find(id: auth()->user()->id); if ($credentials === null || now() > $credentials->expires_at) { $credentials = $this->requestUserToken(); } return $credentials; } /** * Requests a new token for the user & stores it in the database. * * @return ClientCredentials */ private function requestUserToken(): ClientCredentials { $tokenResponse = API::requestToken( client: auth()->user()->client, secret: auth()->user()->secret, ); return ClientCredentials::query()->create( attributes: [ 'user_id' => auth()->user()->id, 'access_token' => $tokenResponse['access_token'], 'refresh_token' => $tokenResponse['refresh_token'], 'token_type' => 'Bearer', 'expires_at' => new DateTime(datetime: '+' . $tokenResponse['expires_in'] . ' seconds') ], ); }