在 PHP 页面上使用 OAUTH API 和 CURL

Using OAUTH API with CURL on a PHP page

我正在使用一个 PHP 网站,我想在其中集成到某个第三方 API。

特别是我正在考虑使用 CURL 与他们的服务器进行交互,但这在这方面我还远不是专家,所以希望社区可以帮助我更好地理解我在做什么。

我不清楚 -X 和 -d 等选项的作用,我也不清楚我如何在我的 PHP 页面上编写此命令的脚本? (不幸的是,google 搜索“-d”很棘手,因为它不被视为搜索字符串的一部分)

我坚持的特定示例是请求访问令牌,提供给我的 API 文档是;

curl -X POST \
-d \ "grant_type=client_credentials&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&scope=REQUESTED_SCOPES" \
'https://api.example.com/token'

grant_type- client_credentials

client_id- Generated during setup

client_secret - Web apps only, generated during setup

scope Optional - List of comma separated values, see supported scopes

If the request is successful, an access token will be returned in the response:

 {
"access_token":"ACCESS_TOKEN",
"token_type":"Bearer",
"expires_in":3600
"scope":"REQUEST_SCOPES"
}

就是上面的指导,我已经完成了先决条件,所以可以确认客户端 ID、密码和所需范围是正确的。

我已经在我的 PHP 脚本中尝试了以下两种方式

$tk = curl_init();

curl_setopt($tk, CURLOPT_URL, "https://api.example.com/token");
curl_setopt($tk, CURLOPT_POST, 1);
curl_setopt($tk, CURL_HTTPHEADER, array('Content-Type: application/json'));
curl_setopt($tk, CURLOPT_POSTFIELDS, array( 'grant_type=client_credentials&client_id=myownid&client_secret=xyz123&scope=instrument'));

// grab URL and pass it to the browser
$result=curl_exec($tk);

// close cURL resource, and free up system resources
curl_close($tk);

$tk = curl_init();

curl_setopt($tk, CURLOPT_URL, "https://api.example.com/token?grant_type=client_credentials&client_id=myownid&client_secret=xyz123&scope=instrument");
curl_setopt($tk, CURLOPT_POST, 1);
curl_setopt($tk, CURL_HTTPHEADER, array('Content-Type: application/json'));

// grab URL and pass it to the browser
$result=curl_exec($tk);

// close cURL resource, and free up system resources
curl_close($tk);

这两个示例都会产生以下错误;

{"error_description":"grant_type parameter is missing","error":"invalid_request"}

任何关于这个特定问题的帮助,甚至只是理解我怎么会出错,给我一些正确语法的想法,都将不胜感激!

提前感谢大家的宝贵时间。

查看下面 php 中 cURL 调用的示例代码。您需要更改您的域名而不是 example.com 还要为 POSTFIELDS 输入值。

$curl = curl_init();

curl_setopt_array($curl, array(
  CURLOPT_URL => "https://api.example.com/oauth/token",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "{\"grant_type\":\"client_credentials\",\"client_id\": \"YOUR_CLIENT_ID\",\"client_secret\": \"YOUR_CLIENT_SECRET\",\"scope\": \"instrument\"}",
  CURLOPT_HTTPHEADER => array(
    "content-type: application/json"
  ),
));

$response = curl_exec($curl);
$err = curl_error($curl);

curl_close($curl);

if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}

如果您想使用 OO 而不是使用 cURL,您可能会更喜欢这个。首先在 Guzzle 中要求:

composer require guzzlehttp/guzzle

创建一个 ApiCredentials 对象:

<?php

namespace Some\Company;

class ApiCredentials
{
    private $clientKey;

    private $clientSecret;

    private $proxy;

    private $baseUrl;

    public function __construct(string $clientKey, string $clientSecret, string $proxy = '', string $baseUrl = 'https://api.somewhere.com')
    {
        $this->clientKey = $clientKey;
        $this->clientSecret = $clientSecret;
        $this->proxy = $proxy;
        $this->baseUrl = $baseUrl;
    }

    public function getClientKey(): string
    {
        return $this->clientKey;
    }

    public function getClientSecret(): string
    {
        return $this->clientSecret;
    }

    public function getProxy(): string
    {
        return $this->proxy;
    }

    public function getBaseUrl(): string
    {
        return $this->baseUrl;
    }
}

现在创建一个 ApiService class:

<?php

namespace Some\Company;

use DateTime;
use GuzzleHttp\Client;

class ApiService
{
    const API_TOKEN_ENDPOINT = '/token';

    private $baseUrl;

    private $client;

    private $accessToken;

    private $credentials;

    public function __construct(ApiCredentials $credentials)
    {
        $this->baseUrl = $credentials->getBaseUrl();
        $options = $this->initOptions($credentials);
        $this->client = new Client($options);
        $this->credentials = $credentials;
    }

    private function initOptions(ApiCredentials $credentials) : array
    {
        $options = [
            'base_uri' => $this->baseUrl,
            'verify'  => false,
        ];
        if ($credentials->getProxy() !== '') {
            $options = \array_merge($options, ['proxy' => [
                'https' => $credentials->getProxy(),
            ]]);
        }

        return $options;
    }

    private function hasAccessToken() : bool
    {
        return $this->accessToken instanceof AccessToken && $this->accessToken->getExpires() > new DateTime();
    }

    private function getAccessToken() : AccessToken
    {
        return $this->accessToken;
    }

    private function getCredentials(): ApiCredentials
    {
        return $this->credentials;
    }

    private function refreshAccessToken()
    {
        $client = $this->getClient();
        $response = $client->post(
            $this->baseUrl . self::API_TOKEN_ENDPOINT, [
            'headers' => [
                'Content-Type' => 'application/x-www-form-urlencoded',
            ],
            'form_params' => [
                'grant_type' => 'client_credentials',
                'client_id' => $this->getCredentials()->getClientKey(),
                'client_secret' => $this->getCredentials()->getClientSecret(),
                'scope' => 'put your scopes in here',
            ],
        ]);
        $json = $response->getBody()->getContents();
        $this->accessToken = new AccessToken($json);
    }

    private function getClient() : Client
    {
        return $this->client;
    }

    private function validateToken()
    {
        if (!$this->hasAccessToken()) {
            $this->refreshAccessToken();
        }
    }

    public function getSomeEndpointData(string $someParam = 'whatever') : string
    {
        $this->validateToken();

        $response = $this->getClient()->get(
            $this->baseUrl . '/get/some/data/' . $someParam, [
            'headers' => [
                'Authorization' => 'Bearer ' . $this->getAccessToken()->getToken(),
            ],
            'query' => [
                'additional' => 'this creates stuff like ?additional=whatever',
            ],
        ]);
        $json = $response->getBody()->getContents();

        return $json;
    }

}

还有一个访问令牌class:

<?php

namespace Some\Company;

use DateTime;

class AccessToken
{
    private $token;

    private $scope;

    private $type;

    private $expires;

    public function __construct(string $tokenJson)
    {
        $token = \json_decode($tokenJson, true);
        $keys = [
            'access_token', 'scope', 'token_type', 'expires_in',
        ];

        $this->token = $token['access_token'];
        $this->scope = $token['scope'];
        $this->type = $token['token_type'];
        $date = new DateTime('+' .$token['expires_in'] . ' seconds');
        $this->expires = $date;
    }

    public function getToken(): string
    {
        return $this->token;
    }

    public function getScope(): string
    {
        return $this->scope;
    }

    public function getType(): string
    {
        return $this->type;
    }

    public function getExpires(): DateTime
    {
        return $this->expires;
    }
}

现在,要使用这些东西:

<?php

use Some\Company\ApiCredentials;
use Some\Company\ApiService;

$clientKey = 'client key key here';
$clientSecret = 'client secret here';
$proxy = 'tcp://199.199.132.132:80'; // optional

$creds = new ApiCredentials($clientKey, $clientSecret, $proxy);
$apiService = new ApiService($creds);

$results = $apiService->getSomeEndpointData('whatever'); // returns json

它也会处理刷新访问令牌等。