首页  >  问答  >  正文

如何使用 Laravel 的服务提供程序进行外部 API 使用(利用基于用户的凭据)

所以我正在开发一个 Laravel 管理应用程序,它使用外部 API,我们称之为 PlatformAPI。平台的工作方式是,我的应用程序的用户在平台上有一个帐户。我的 Laravel 应用程序将充当管理仪表板,因此用户可以查看一些从 PlatformAPI 获取的基本报告。

我的应用程序中的每个用户都必须添加他们的客户端 ID 和客户端密钥,他们可以在平台中创建这些内容。这样,我的应用程序将能够使用用户的凭据代表他们向 PlatformAPI 执行请求。

我读过一些文章和教程,基本介绍了如何为服务设置凭据/令牌并将该服务绑定到 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 时都设置客户端凭据,我可以像这样调用该服务:

<?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);
    }
}

但是,由于我需要代表我的应用程序的用户使用他们提供的凭据(并存储在我的应用程序的数据库中)向 PlatformApi 执行请求,所以我不确定这种相同的方法是否有效,因为单例只能实例一次?

此外,为了使用 PlatformApi,我需要使用用户的凭据获取访问令牌。该访问令牌也需要存储在某个地方(我想在缓存中)。

我有点不知道如何解决这个问题。任何指示将不胜感激。

P粉465675962P粉465675962334 天前444

全部回复(1)我来回复

  • P粉523625080

    P粉5236250802023-12-14 13:41:31

    我假设您的所有应用程序都将使用此客户端服务。如果是这样,您可以继续使用单例设计模式(以停止进一步的 oauth 请求),但尝试将逻辑与提供程序的 register 方法分开。您可以在调用返回有效 access_token 的私有方法后实例化 Client 类(如果存在有效令牌,则检查 DB / Cache expires_in 时间戳值并返回它,或者向用户请求一个新的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')
                ],
            );
        }

    回复
    0
  • 取消回复