PayPal REST 令牌请求:api.paypal.com OK,api-m 失败

Posted

技术标签:

【中文标题】PayPal REST 令牌请求:api.paypal.com OK,api-m 失败【英文标题】:PayPal REST token request: api.paypal.com OK, api-m fails 【发布时间】:2021-12-23 10:16:53 【问题描述】:

附录 2:Mozilla 行为特定于 URL 解析到的主机;我在问题末尾添加了显示此内容的 curl 脚本。

附录:这在 8 小时左右后消失了,并且工作了几天。但是一周后,我重新运行该页面只是为了检查,它再次重复失败:api.paypal 有效,api-m.paypal 无效。

我从 api-m.paypal.com 和 api.paypal.com 收到不同的请求实时站点访问令牌的结果。如果我向 api.paypal.com 发出请求,它会起作用并返回一个令牌。如果我从 api-m.paypal.com 请求它,我会收到 403 Forbidden 错误。这怎么可能?一般来说,对于令牌请求,文档似乎可以互换使用 api 和 api-m。两者有什么区别,哪些调用应该路由到 api vs api-m?当我在沙盒上运行我的整个商店时,一切 都会转到 api-m 并且工作正常。在一个只是重复请求令牌的测试程序中,通过 api、api-m、api.sandbox 和 api-m.sandbox 排序——只有 api-m 失败,其他 3 种情况都很好。我看过一次 api vs api-m 的讨论,但找不到了;很确定它没有提到这个!

<?php

include("../_private/ppinfo.php");

header('Content-type: text/plain');
$sandbox = 0;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = 1;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = 2;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = -1;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = 0;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = -1;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = 1;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = 0;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";
$sandbox = 2;
echo "sandbox $sandbox rv " . GetNewPPToken($sandbox) . "\n";

// Get a paypal REST token to use for the rest of our transactions.
// See https://developer.paypal.com/docs/business/get-started/

function GetNewPPToken($sandbox) 

    global $G, $ppinfo;

    $headers = array(
            "Accept: application/json",
            "Accept-Language: en_US",
            "Content-Type: application/x-www-form-urlencoded"
        );
    if ($sandbox > 1)
    
    $clid = $ppinfo['sb_acct'];
    $secret = $ppinfo['sb_secr'];
    $url = "https://api.sandbox.paypal.com/v1/oauth2/token";
    
    else if ($sandbox > 0)
    
    $clid = $ppinfo['sb_acct'];
    $secret = $ppinfo['sb_secr'];
    $url = "https://api-m.sandbox.paypal.com/v1/oauth2/token";
    
    else if ($sandbox < 0)
    
    $clid = $ppinfo['acct'];
    $secret = $ppinfo['secr'];
    $url = "https://api.paypal.com/v1/oauth2/token";
    
    else
    
    $clid = $ppinfo['acct'];
    $secret = $ppinfo['secr'];
    $url = "https://api-m.paypal.com/v1/oauth2/token";
    ;

    $cvt = "grant_type=client_credentials";
    $curl = newPPcurl($url, $cvt, $headers);
    curl_setopt($curl, CURLOPT_USERPWD, "$clid:$secret");
    $resp = curl_exec($curl);
    $err = curl_error($curl) ;
    $json = json_decode($resp, true);

    if (0)
    
    echo "response:\n";
    print_r($resp);
    echo "err:\n";
    print_r($err);
    echo "token '" . $ppinfo['token'] . "'\n";
    ;

    $ppinfo['token'] = $json['access_token'];
    return ($ppinfo['token'] != '' ? 1 : 0);




function newPPcurl($url, $flds, $hdrs)

    $user_agent = "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)";

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_POST, 1);
    if ($flds != '')
    curl_setopt($curl, CURLOPT_POSTFIELDS, $flds);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_FORBID_REUSE, 1);
    curl_setopt($curl, CURLOPT_USERAGENT, $user_agent);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST,  2); // or 2?
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, TRUE);
    //curl_setopt($curl, CURLOPT_SSLCERT, $pem);  // pem file name
    curl_setopt($curl, CURLOPT_TIMEOUT, 30);
    curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
    if ($hdrs != "")
    curl_setopt($curl, CURLOPT_HTTPHEADER, $hdrs);

    return $curl;

测试输出:

sandbox 0 rv 0
sandbox 1 rv 1
sandbox 2 rv 1
sandbox -1 rv 1
sandbox 0 rv 0
sandbox -1 rv 1
sandbox 1 rv 1
sandbox 0 rv 0
sandbox 2 rv 1

这里有一些显示这种行为的 curl 命令。当 api-m.paypal.com 解析为 184.87.90.6 时,可以使用 Mozilla 代理 (cmd #1) 获取令牌。当 IP 解析为 151.101.1.35 时,Mozilla (cmd#2) 的请求失败,curl (cmd#3) 通过。请注意,您必须提供自己的 id:pwd 字符串进行测试。

curl -v https://api-m.paypal.com/v1/oauth2/token \
    --user-agent "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" \
    --resolve api-m.paypal.com:443:184.87.90.6 \
  -H "Accept: application/json" \
  -H "Accept-Language: en_US" \
  -u "<id:pwd>" \
  -d "grant_type=client_credentials"
curl -v https://api-m.paypal.com/v1/oauth2/token \
    --user-agent "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" \
    --resolve api-m.paypal.com:443:151.101.1.35 \
  -H "Accept: application/json" \
  -H "Accept-Language: en_US" \
  -u "<id:pwd>" \
  -d "grant_type=client_credentials"
curl -v https://api-m.paypal.com/v1/oauth2/token \
    --user-agent "curl/7.55.1" \
    --resolve api-m.paypal.com:443:151.101.1.35 \
  -H "Accept: application/json" \
  -H "Accept-Language: en_US" \
  -u "<id:pwd>" \
  -d "grant_type=client_credentials"

【问题讨论】:

你能用命令行 curl (no PHP) 重现这个行为吗?或者在 PHP 中使用 Guzzle 等库? 好主意,curl 工作...直到我设置了用户代理。 【参考方案1】:

PayPal REST 令牌请求的用户代理必须是 curl 标识符,例如“curl/7.55.1”。 使用 Mozilla 用户代理会导致 api-m.paypal.com 上的 403 FORBIDDEN ,尽管它似乎适用于 api.paypal.com、api.sandbox.paypal.com 和 api-m.sandbox.paypal.com

【讨论】:

您使用的是什么用户代理?使用 curl 7.64.1 和标志 -A "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:94.0) Gecko/20100101 Firefox/94.0" 到 url https://api-m.paypal.com/v1/oauth2/token 进行测试,它对我来说很好。 “Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)”上面源码中的那个 根据 URL 解析到的服务器,我看到了不同的响应。使用 Mozilla 可以正常工作:184.87.90.6.. 不工作:151.101.1.35。我能够使用 curl ... --resolve 进行验证。 (在上面的 Q 中添加 curl) @PrestonPHX 在玩 tracert 时,我发现其他 IP 地址在 Mozilla 中失败,通过 Curl 用户代理字符串传递:151.101.1.35 151.101.65.35 与 Mozilla 一起传递的是 akamai 镜像,失败的是 api-m-fastly.glb.paypal.com 地址。 有趣的是,只有 Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0) 失败了,尤其是由于 MSIE 5.01。那是一个相当古老的用户代理!看起来 MSIE 必须至少为 6 或更高,但即使这样也太老了。

以上是关于PayPal REST 令牌请求:api.paypal.com OK,api-m 失败的主要内容,如果未能解决你的问题,请参考以下文章

PayPal REST API:代表商家发出请求

访问 PayPal 沙箱 Rest API 时响应 401

通过 OAuth 代表商家发出 PayPal REST API 请求

Paypal Rest API - 来自批准 URL 的令牌生命周期

paypal rest sdk - 取消付款只提供令牌

PayPal Rest SDK API - 获取令牌