如何使用 PayPal REST API 和 IPN 验证销售

Posted

技术标签:

【中文标题】如何使用 PayPal REST API 和 IPN 验证销售【英文标题】:How to validate a sale with PayPal REST API and IPN 【发布时间】:2016-08-08 14:41:31 【问题描述】:

我目前通过 PayPal _xcart 方法有一个完整的购物车和结帐流程,但我想将其迁移到 REST API,主要是因为我想减少价格劫持的可能性。目前,我的 IPN 会检查价格插孔并设置相应的标志,因此不会下载产品(仅销售数字产品)。无论如何,更重要的是,我发现 PayPal 文档非常混乱,我很难完全掌握它。

这是我到目前为止所理解和解决的。

    使用我的 php 脚本(我们称之为页面 A)创建购物车内容,然后创建新的 PayPal 销售并将客户端重定向到 PayPal 进行身份验证

    在 PayPal 上进行客户端身份验证,然后将其重定向回我的站点到页面 B(页面 B 在页面 A 中定义)

    页面 B 需要获取 PaymentID(来自页面 A)并使用它来有效地完成交易。一旦比赛完成结帐。

现在这是我的问题:

a) 我已经阅读了很多论坛和教程,他们都提到我应该使用会话来存储页面 A 中的 PaymentId,然后在页面 B 中使用它来完成交易。 SO上的一些线程建议PayPal实际上应该在对页面B的调用中包含PaymentID,以及令牌和PayerID。这些都是近 3 年的帖子,在我的测试过程中,我发现 PayPal 现在也确实返回了 PaymentID。

这是一个新事物吗,PayPal 真的开始将 PaymentID 作为 GET 变量发送吗? 好的,我在 PayPal SDK 文档(当然不是 PHP,当然是其他语言)上发现他们也返回了 PaymentID作为 GET。 与将会话从页面 A 存储到 B 相比,使用 PayPal 提供的 GET 有什么缺点吗?我真的不想要会话,所以 GET 对我来说是理想的选择。我想如果它在 PayPal 文档中,它可以安全使用。 此功能是否也适用于实时页面或仅适用于沙盒?

b) 在页面 B 上,当我执行付款时,我得到一个很好的 JSON 作为响应,但同时我的 IPN 侦听器也被调用,这让我很困惑。我可以/应该只信任 JSON 响应中的所有数据,或多或少地忽略 IPN 侦听器吗?这对于即时下载是有意义的,例如,更容易处理,还是我仍然应该依赖 IPN 进行数据验证?

如果我只使用返回到页面 B 的 JSON,哪些是要查找的正确字段以及哪些值?例如,有一个状态字段被批准,另一个(交易 -> 相关项目 -> 状态)是竞争的。我需要检查哪一项? 如果我依赖 JSON,我是否还需要检查支付的金额是否与原始金额相符,或者我是否可以相信支付的金额等于我在通话中请求的金额? 如果我使用 IPN,我如何将它与交易配对? PaymentID 不会显示在发布到 IPN 的变量中。我能想到的唯一方法是从 JSON 响应中获取 txn_id,但不知何故感觉很奇怪,另外我怎么知道 JSON 响应是否在 IPN 之前到达服务器?

【问题讨论】:

所以你基本上是在说“请不要将我链接到我的问题的答案。” ;) 你也可以这样说,除非指向某处的链接是用白底黑字写成的(对于 PayPal 官方颜色也可以在白色上写),但说明和参考应该清晰易懂... 【参考方案1】:

我可以/应该只信任 JSON 响应中的所有数据而或多或少地忽略 IPN 侦听器吗?

是的,也不是。按这个顺序。

简而言之,您不能信任对“页面 B”的调用中的付款 ID(它可能是伪造、伪造、重复等),但您可以信任响应 YourServer->PayPalServer,因为它不可能被最终用户拦截和伪造。

所以你的过程是(如上所述)

    页面 A:创建 sessionID (cookie)、金额、购物车详细信息等并存储在本地数据库/存储中。您还可以创建一个“自定义”字段来存储您自己的 saleID 将金额等发送到 Paypal,Paypal 会将您退回到 .... 页面 B:获取 PayPal TransactionID 并将 (server->server) 发送回 PayPal。 Paypal 返回金额、状态等。然后检查您的数据库,金额是否相同并且属于 sessionID。如果您还使用自定义字段,请也检查一下。如果一切都结婚了,那你很好。如果没有,那取决于你如何处理。

此时简单销售的状态应该是“完成”;但是(与下面的 IPN 一样)您应该验证这一点。

请检查金额,以防万一。它们应该匹配,但如果不匹配,PayPal 将是您收到的内容,您可以接受、标记(并打电话)或通过 API 退款并拒绝订单等。

那么为什么要有 IPN?

有可能用户在 Paypal 上完成了交易,然后在调用“页面 B”之前关闭了浏览器。在这种情况下,您了解订单的唯一方法是通过 IPN。

如果您收到发送至您的 IPN 处理程序的 IPN 通知,则 IPN 仍可能被伪造,但验证方式略有不同。

您实际上将 IPN 信息发送回 Paypal(服务器到服务器),Paypal 确认它是正确还是错误 (https://developer.paypal.com/docs/classic/ipn/integration-guide/IPNIntro/)。然后,您的 IPN 处理程序将检查事务 ID(是的,这就是您使用的)并验证数据库中的所有内容是否匹配(就像您在“页面 B”中所做的那样)。如果是,则在状态为完成的情况下将订单标记为完成(如果尚未在“页面 B”中标记为完成)。

显然,此时您无法向用户显示任何内容,因为他们不是调用页面的人。

上面的文档警告您,您可以为同一笔交易获得多个 IPN,因此您还需要检查状态。

(注意:您可以像在“页面 B”中那样使用 API 来验证 transactionID)。

那么为什么不在 IPN 上回复呢?

Paypal 警告 IPN 可能无法到达。 Paypal 解释得最好:

虽然 PayPal 通常会立即处理 IPN 消息,但 IPN 不会与您网站上的操作同步。 Internet 连接并不总是 100% 可靠,IPN 消息可能会丢失或延迟。 IPN 服务会自动重新发送消息,直到侦听器确认它们为止。该服务最多会重新发送消息 4 天。

由于 IPN 不是实时服务,因此您的结帐流程不应等待 IPN 消息才允许完成。如果结帐流程依赖于接收 IPN 消息,则处理可能会因系统负载或其他原因而延迟。您应该配置结帐流程以处理可能的延迟。

回到原来的问题

是的:依靠您进行的 JSON (server->server) 调用来验证“Page B”的参数(如果您选择,还可以在 IPN 处理程序中)

否:不要忽略 IPN,以防页面 B 永远不会被调用。但仍然在这里运行验证检查。

是:检查状态 =“页面 B”和“IPN 处理程序”的完成

是:使用 Paypal TransactionID,但将自定义字段或 sessionID 混合到您自己的数据库中。

是的,您可以/将会同时收到页面 B 和 IPN 通知,如果付款已标记为已完成,我建议您忽略 IPN,否则会适当处理和处理。他们应该使用相同的数据库。

【讨论】:

谢谢。漂亮而清晰的解释(用简单的英语)使事情变得清晰。如果您知道,我可以要求小额充值吗?如果 API 响应处于待处理状态而不是已完成(电子支票、可能的欺诈等),我想我将不得不等待 IPN 通知(在稍后阶段),该通知将完成/拒绝/取消该付款,对吧? 没错。只需显示“等待清算资金 - 当您的订单完成时我们会通过电子邮件发送给您”,更新您的数据库(以便您可以在以后跟进)并等待 IPN。如果 IPN 从未通过,您可能需要定期运行手动检查,因为 PayPal 希望 IPN 可能会失败。 (不过,我实际上从未有过未决或不同的金额,但为它编写代码。) 这个答案关于 IPN 的使用是不正确的。如果批准后重定向失败,IPN 无能为力,因为授权支付不会执行,IPN 也不会发送。它仅在执行付款后发送。在新的 REST 工作流程中,我看不到 IPN 的任何用途。 REST 工作流确实有一个弱点,它依赖于重定向,因此依赖于客户端的浏览器来通过批准。他们消除了 Paypal 页面上的 10 秒延迟,但仍然可以在收到重定向之前关闭浏览器。 IPN 无能为力。 你能澄清一下答案的哪一点不正确吗?答案并不涉及如果付款不通过会发生什么 - 正如您所指出的如果没有发生授权付款,那么您将不会获得 IPN。但在这种情况下,您不需要(或想要)IPN。如答案中所述,您应该(但不能保证)获得已完成付款的 IPN,如果通过浏览器的流程未完成,您可以将其用作二级备份 - 这就是它适合工作流程的地方。这不是必需的,但它是一个安全网。 感谢您的出色回答。 IPN 包括 txn_id,它对应于从 REST API 获得的 CaptureID。但是,要获取有关交易的信息,需要订单 ID,该 ID 不包含在 IPN 中。多么不方便!

以上是关于如何使用 PayPal REST API 和 IPN 验证销售的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 PayPal REST API 和 IPN 验证销售

如何在使用 PayPal rest API 执行付款之前更改运费

通用对象定义 - PayPal REST API - 它是啥?如何使用?

如何使用 PayPal PHP REST API 设置帐单或送货地址?

如何在 c# 中使用 rest api 进行 paypal 卡存在(刷卡)付款?

PayPal Rest API:如何将卡添加或更新到计费协议 api?