Paypal 结帐 - 订单捕获从服务器获得 PERMISSION-DENIED 但在 javascript 客户端中工作

Posted

技术标签:

【中文标题】Paypal 结帐 - 订单捕获从服务器获得 PERMISSION-DENIED 但在 javascript 客户端中工作【英文标题】:Paypal checkout - order capture get PERMISSION-DEINED from server but works in javascript client 【发布时间】:2021-11-22 00:04:50 【问题描述】:

我正在使用 Paypal 结帐 php sdk。我从这里关注文档https://github.com/paypal/Checkout-PHP-SDK

首先我创建一个订单

$env = new SandboxEnvironment($clientId, $secretKey);

$client = new PayPalHttpClient($env);

$request = new OrdersCreateRequest();

$request->prefer('return=representation');

$request->body = buildOrder($order);

//buildOrder has this param:
/*
"application_context" => [
     "return_url" => 'domain/paypal/return.php',
     "cancel_url" => 'domain/paypal/cancel.php'
 ]
*/

//request body
$body = array (
  'intent' => 'CAPTURE',
  'purchase_units' => 
  array (
    0 => 
    array (
      'reference_id' => 9,
      'amount' => 
      array (
        'value' => 125.63,
        'currency_code' => 'USD',
        'breakdown' => 
        array (
          'item_total' => 
          array (
            'currency_code' => 'USD',
            'value' => 125.63,
          ),
        ),
      ),
      'items' => 
      array (
        0 => 
        array (
          'name' => 'Demo 46',
          'description' => NULL,
          'sku' => NULL,
          'unit_amount' => 
          array (
            'currency_code' => 'USD',
            'value' => 98.0,
          ),
          'quantity' => '1',
        ),
        1 => 
        array (
          'name' => 'Demo 28',
          'description' => NULL,
          'sku' => NULL,
          'unit_amount' => 
          array (
            'currency_code' => 'USD',
            'value' => 12.22,
          ),
          'quantity' => '1',
        ),
        2 => 
        array (
          'name' => 'Addon 33',
          'description' => NULL,
          'sku' => NULL,
          'unit_amount' => 
          array (
            'currency_code' => 'USD',
            'value' => 15.41,
          ),
          'quantity' => '1',
        ),
      ),
    ),
  ),
  'application_context' => 
  array (
    'return_url' => 'http://domain.test/paypal/return',
    'cancel_url' => 'http://domain.test/paypal/canceled',
  ),
)
$response = $client->execute($request);

创建订单响应:

"statusCode":201,"result":"id":"10M47599SM3059709","intent":"CAPTURE","status":"CREATED","purchase_units":["reference_id":"9","amount":"currency_code":"USD","value":"125.63","breakdown":"item_total":"currency_code":"USD","value":"125.63","payee":"email_address":"sb-kpo1v7959755@business.example.com","merchant_id":"XEH8BEAE3FXPW","items":["name":"Demo 46","unit_amount":"currency_code":"USD","value":"98.00","quantity":"1","name":"Demo 28","unit_amount":"currency_code":"USD","value":"12.22","quantity":"1","name":"Addon 33","unit_amount":"currency_code":"USD","value":"15.41","quantity":"1"]],"create_time":"2021-09-30T22:59:31Z","links":["href":"https:\/\/api.sandbox.paypal.com\/v2\/checkout\/orders\/10M47599SM3059709","rel":"self","method":"GET","href":"https:\/\/www.sandbox.paypal.com\/checkoutnow?token=10M47599SM3059709","rel":"approve","method":"GET","href":"https:\/\/api.sandbox.paypal.com\/v2\/checkout\/orders\/10M47599SM3059709","rel":"update","method":"PATCH","href":"https:\/\/api.sandbox.paypal.com\/v2\/checkout\/orders\/10M47599SM3059709\/capture","rel":"capture","method":"POST"],"headers":"":"","Content-Type":"application\/json","Content-Length":"1085","Connection":"keep-alive","Date":"Thu, 30 Sep 2021 22","Application_id":"APP-80W284485P519543T","Cache-Control":"max-age=0, no-cache, no-store, must-revalidate","Caller_acct_num":"XEH8BEAE3FXPW","Paypal-Debug-Id":"95be3b11c12e7","Strict-Transport-Security":"max-age=31536000; includeSubDomains"

然后我可以得到orderID,我将它存储在会话中。接下来,我将买家重定向到来自 Paypal 响应的 approve url。

接下来,买家付款,Paypal 将买家带到我上面的退货网址。

在return.php中我通过这段代码捕获订单

$env = new SandboxEnvironment($clientId, $secretKey);

$client = new PayPalHttpClient($env);

//$orderId can get from session or from `token` param in return url
$request = new OrdersCaptureRequest($orderId);

$request->prefer('return=representation');


$response = $client->execute($request);

来自 OrdersCaptureRequest 的新响应:

"name":"NOT_AUTHORIZED","details":["issue":"PERMISSION_DENIED","description":"You do not have permission to access or perform operations on this resource."],"message":"Authorization failed due to insufficient permissions.","debug_id":"e8021203038f1","links":["href":"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED","rel":"information_link"] "exception":"[object] (PayPalHttp\\HttpException(code: 0): \"name\":\"NOT_AUTHORIZED\",\"details\":[\"issue\":\"PERMISSION_DENIED\",\"description\":\"You do not have permission to access or perform operations on this resource.\"],\"message\":\"Authorization failed due to insufficient permissions.\",\"debug_id\":\"e8021203038f1\",\"links\":[\"href\":\"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED\",\"rel\":\"information_link\"]

我的回复是(旧的):

"name":"NOT_AUTHORIZED","details":["issue":"PERMISSION_DENIED","description":"You do not have permission to access or perform operations on this resource."],"message":"Authorization failed due to insufficient permissions.","debug_id":"ff1bfd34831cb","links":["href":"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED","rel":"information_link"] "exception":"[object] (PayPalHttp\\HttpException(code: 0): \"name\":\"NOT_AUTHORIZED\",\"details\":[\"issue\":\"PERMISSION_DENIED\",\"description\":\"You do not have permission to access or perform operations on this resource.\"],\"message\":\"Authorization failed due to insufficient permissions.\",\"debug_id\":\"ff1bfd34831cb\",\"links\":[\"href\":\"https://developer.paypal.com/docs/api/orders/v2/#error-PERMISSION_DENIED\",\"rel\":\"information_link\"]

然后我提出了在客户端和服务器之间结合的解决方案

    我嵌入了 Paypal 结帐按钮 从服务器创建订单 处理来自 js 客户端的批准 通过 Paypal js 函数捕获订单。 Paypal 以COMPLETED 状态回复。
<script
            src="https://www.paypal.com/sdk/js?client-id=[SANDBOX_CLIENT_ID]"></script>
<script>
paypal.Buttons(
            createOrder: function(data, actions)
                return fetch('create-order.php', 
                    method: 'post',
                    headers: 
                        'content-type': 'application/json'
                    ,
                ).then(function(res) 

                    return res.json();
                ).then(function(data) 

                    return data.token;
                );
            ,
            onApprove: function(data, actions)
                return actions.order.capture().then(function(details)
                   console.log(details);
                );
            
);
</script>

即使我尝试将 Paypal js 的 onApprove 事件中的 orderID 发送到我的服务器以捕获订单,PERMISSION-DENIED 也会发生同样的问题。

请帮忙。

【问题讨论】:

【参考方案1】:

重定向到 rel:approve URL 适用于旧网站。您应该使用 PayPal 按钮而不是重定向,这对买家来说是一种更好、更现代的上下文体验,让您的网站在后台加载/灯箱褪色。

您在服务器端捕获订单时遇到的问题似乎是使用了错误的请求对象:

//$orderId can get from session or from `token` param in return url
$request = new OrdersCreateRequest($orderId);

在这个阶段,您需要一个 OrdersCaptureRequest。请参阅示例bundled as part of the SDK。

【讨论】:

感谢您的建议。我使用了 Paypal 按钮,但我想从服务器而不是 Paypal javascript 捕获订单。对于 OrdersCreateRequest,这是我复制粘贴的错误。事实上,我使用了 OrdersCaptureRequest,编辑了我的问题。 (1) 在 paypal.com/… 中创建一个新的沙盒业务帐户 (2) 在 paypal.com/… 中为该帐户创建一个新的 REST 应用程序 (3) 在任何地方使用新APP的Client ID和Secret,包括在你的API调用和JS SDK中。如果问题仍然存在,请记录您的完整订单 创建和订购 Capture API 调用(包括请求和响应文本)并使用此信息以及您正在使用的新沙盒客户端 ID 和秘密凭据更新您的问题。 我创建了新的企业帐户,为该企业帐户创建了新的应用程序。我用更多细节编辑了这个问题。谢谢@Preston 我在您的编辑中没有看到任何不正确的地方,但您没有包含您正在使用的沙盒客户端 ID 和密码,因此无法对其进行测试以进行重现。接下来您应该尝试的是从paypal.com/… 新创建的个人帐户,以确保买家帐户正常

以上是关于Paypal 结帐 - 订单捕获从服务器获得 PERMISSION-DENIED 但在 javascript 客户端中工作的主要内容,如果未能解决你的问题,请参考以下文章

PayPal 结帐:不允许仅使用客户 ID 创建订单/订阅

PayPal 订阅 API - 如何应用折扣

Paypal 快速结帐错误订单总额丢失。错误 10400

我如何获得这种类型的 Paypal 结帐页面?

Paypal 订单信息/数据采集

在magento中自动从paypal捕获付款