【问题标题】:Apple In-App Purchase Receipt - validation on the server-sideApple In-App Purchase Receipt - 服务器端验证
【发布时间】:2015-03-12 12:31:22
【问题描述】:

我在服务器端验证苹果收据时遇到问题。 我试图在互联网上找到解决方案,但没有成功。

所以,描述: 首先,应用程序是为iOS7制作的。其次,我有一些项目( type = Non-Renewing Subscription )。所以用户可以购买一件或多件商品,然后他应该手动更新它们(再次购买)。

应用程序向服务器端发送收据,我向 Apple 发出请求并获得 很多 in_app 收据的结果。比如:

"in_app":[
{
"quantity":"1", "product_id":"...", "transaction_id":"...",
"original_transaction_id":"...", "purchase_date":"...", 
"purchase_date_ms":"...", "purchase_date_pst":"...", 
"original_purchase_date":"...", 
"original_purchase_date_ms":"...", "original_purchase_date_pst":"...",
"is_trial_period":"..."}, 
{
"quantity":"1", "product_id":"...", 
"transaction_id":"...","original_transaction_id":"...", 
"purchase_date":"...", "purchase_date_ms":"...", 
"purchase_date_pst":"...", "original_purchase_date":"...", 
"original_purchase_date_ms":"...", "original_purchase_date_pst":"...", 
"is_trial_period":"..."}
]

因此,“in_app”中的每个“收据”都有 transaction_id。但是如何识别当前购买的 transactionId 呢?我也想验证它并确保它是唯一的。

我担心的是:如果有人获得一张有效收据,他将能够破解我们的服务器端 API,并使用同一张有效收据进行无限数量的应用内购买。

我是否应该以某种方式解密并检查“原始”收据的 transaction_id,即我发送给 Apple 进行验证的那张?

任何帮助/建议将不胜感激。 提前谢谢你。

问候, 马克西姆

【问题讨论】:

  • 大声笑我只是想问同样的问题。我偶然发现了这个,看到你在 8 小时前问过这个......这只是 sux,我也不知道要做什么处理所有这些收据...
  • 我想在这里做同样的检查。我希望有人看到并回答它! :\
  • 我认为关键是在 app 端获取当前购买的交易 id,并将其与收据一起发送到服务器。你可以从事务对象中获取应用端的事务id。
  • 感谢您的评论。但这是该方法的缺点:无法理解此收据与此交易 id 相关。

标签: ios in-app-purchase


【解决方案1】:

@道格·史密斯

https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html

如果您浏览此页面上的不同字段,您会发现

原始交易标识符:: 对于恢复先前交易的交易,原始交易的交易标识符。否则,与事务标识符相同。 此值对应于原始交易的 transactionIdentifier 属性。 自动续订订阅的续订链中的所有收据在此字段中具有相同的值。

因此,对于您的非自动续订订阅,您必须在服务器端跟踪两件事:

  1. 您正在使用 iTunes 服务器验证收据的原始交易标识符,将其与数据库中的用户 ID 相关联。
  2. 您从客户端收到的请求是购买还是恢复购买。

一旦你有了这两个东西,你就可以在这两个参数上写下你的逻辑,如下所示:

::如果请求的类型为“购买”,并且您已经拥有与其他用户 ID 相关联的收据的原始交易标识符,则可以阻止该购买。

::如果请求的类型为“恢复购买”并且请求来自与您的数据库中的原始事务标识符相关联的同一用户 ID,则允许他阻止他的恢复。

此外,您可以根据自己的需要,根据这些东西推导出自己的逻辑。

如果您还有任何疑问,请告诉我。

【讨论】:

  • 我的问题是 transaction_id 属性永远不会从收据 JSON 中的原始属性更新。
  • 但是您收到两个 JSON 格式的字典。一个对应于原始交易,另一个对应于您刚刚执行的交易。
【解决方案2】:

对于每笔新交易,苹果都会发送一个新的收据,该收据是唯一的,对其进行编码,这样任何人都无法伪造数据。

从完成的交易中获取交易回执,将其编码并发送到您的服务器,并在服务器端对其进行解码并与发送到服务器的一个苹果匹配。

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
{
    _transactionArray = transactions;
    for (SKPaymentTransaction * transaction in transactions)
    {
        switch (transaction.transactionState)
        {
            case SKPaymentTransactionStatePurchased: {
                NSData *receipt = transaction.transactionReceipt;
                [self sendReceiptToServer];
            } break;

            case SKPaymentTransactionStateFailed: {
                // finish this transaction
            } break;

            case SKPaymentTransactionStateRestored:
                NSData *receipt = transaction.transactionReceipt;
                [self sendReceiptToServer:receipt];
            } break;

            default:
                break;
        }
    };
}


-(void)sendReceiptToServer:(NSData *)receipt {
    // encode receipt
    // send receipt to server
    // add success and error callback
}

-(void) receiptSuccess {
    // finish transaction here
}

-(void) receiptError {
    // try again sending receipt to server
}

【讨论】:

  • 此代码的一些问题:1) - [SKPaymentTransaction transactionReceipt] 自 iOS7 以来已弃用,应使用 [[NSBundle mainBundle] appStoreReceiptURL]。 2) 无论交易完成状态如何,交易都应该完成,因此在所有情况下都应该调用-[SKPaymentQueue finishTransaction:](默认情况除外)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-13
  • 2017-01-11
  • 1970-01-01
  • 2018-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多