1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | import json import requests SAND_BOX_VERIFY_URL = 'https://sandbox.itunes.apple.com/verifyReceipt' VERIFY_URL = 'https://buy.itunes.apple.com/verifyReceipt' # /** # * 服务器二次验证代码 # * 21000 App Store不能读取你提供的JSON对象 # * 21002 receipt-data域的数据有问题 # * 21003 receipt无法通过验证 # * 21004 提供的shared secret不匹配你账号中的shared secret # * 21005 receipt服务器当前不可用 # * 21006 receipt合法,但是订阅已过期。服务器接收到这个状态码时,receipt数据仍然会解码并一起发送 # * 21007 receipt是Sandbox receipt,但却发送至生产系统的验证服务 # * 21008 receipt是生产receipt,但却发送至Sandbox环境的验证服务 # */ def verify_receipt_with_apple(receipt, is_sandbox=False): jsonStr = json.dumps({"receipt-data": receipt}) headers = {'Content-Type': 'application/json'} url = VERIFY_URL if is_sandbox: url = SAND_BOX_VERIFY_URL rep = requests.post(url=url, data=jsonStr, headers=headers) # print(rep.text) return rep.text def verify_receipt_with_apple_json(receipt, is_sandbox=False): resp = verify_receipt_with_apple(receipt, is_sandbox) try: json_data = json.loads(resp) except: return None return json_data if __name__ == "__main__": receipt = "MIITrQYJKoZIhvcNAQcCoIITnjCCE5oCAQExCzAJBgUrDgMCGg" js = verify_receipt_with_apple_json(recpt, True) print(js['receipt']) print(js['receipt']['in_app']) print(js['receipt']['in_app'][0]) |
服务器的校验代码相对来说并没有什么比较复杂的内容,但是返回的数据确比较让人抑郁。苹果的服务器返回的的receipt并不包含任何的用户信息,也不会包含购买的物品信息。于是要想知道买的什么东西就比较麻烦。
其实服务器在进行数据校验的时候最好一起把transactionID一起发送带服务器进行校验处理。因为苹果的验证服务器会返回多个收据信息,在in-app中包含的数据并没有按照时间或者特定的顺序进行排列,所以从其他地方看到的直接获取最后的一条in-app信息来获取购买的数据是存在问题的。可以通过in-app中的transactionID字段来获取最后买的数据。
例如,客户端在完成购买之后获取的信息为:
{ "transactionID": "1000000625912120", "currencyCode": "CNY", "receiptCipheredPayload": "MIITtAYJKWc=", "title": "小袋", "receipt": "", "price": "¥6.00", "id": "test01", "priceValue": 6, "description": "小袋,用于应用内的审核", "name": "small_one" } |
在校验之后返回的数据同样可以拿到包含这个字段的in-app数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | { 'receipt': { 'receipt_type': 'ProductionSandbox', 'adam_id': 0, 'app_item_id': 0, 'bundle_id': 'obaby.mars.game', 'application_version': '1.0', 'download_id': 0, 'version_external_identifier': 0, 'receipt_creation_date': '2020-02-17 08:43:26 Etc/GMT', 'receipt_creation_date_ms': '1581929006000', 'receipt_creation_date_pst': '2020-02-17 00:43:26 America/Los_Angeles', 'request_date': '2020-02-17 08:43:33 Etc/GMT', 'request_date_ms': '1581929013522', 'request_date_pst': '2020-02-17 00:43:33 America/Los_Angeles', 'original_purchase_date': '2013-08-01 07:00:00 Etc/GMT', 'original_purchase_date_ms': '1375340400000', 'original_purchase_date_pst': '2013-08-01 00:00:00 America/Los_Angeles', 'original_application_version': '1.0', 'in_app': [{ 'quantity': '1', 'product_id': 'viptest01', 'transaction_id': '1000000627719846', 'original_transaction_id': '1000000627719846', 'purchase_date': '2020-02-17 08:14:47 Etc/GMT', 'purchase_date_ms': '1581927287000', 'purchase_date_pst': '2020-02-17 00:14:47 America/Los_Angeles', 'original_purchase_date': '2020-02-17 08:14:47 Etc/GMT', 'original_purchase_date_ms': '1581927287000', 'original_purchase_date_pst': '2020-02-17 00:14:47 America/Los_Angeles', 'is_trial_period': 'false' }, { 'quantity': '1', 'product_id': 'viptest02', 'transaction_id': '1000000625912120', 'original_transaction_id': '1000000625912120', 'purchase_date': '2020-02-17 06:44:13 Etc/GMT', 'purchase_date_ms': '1581921853000', 'purchase_date_pst': '2020-02-16 22:44:13 America/Los_Angeles', 'original_purchase_date': '2020-02-17 06:44:13 Etc/GMT', 'original_purchase_date_ms': '1581921853000', 'original_purchase_date_pst': '2020-02-16 22:44:13 America/Los_Angeles', 'is_trial_period': 'false' }, { 'quantity': '1', 'product_id': 'viptest02', 'transaction_id': '1000000627681920', 'original_transaction_id': '1000000627681920', 'purchase_date': '2020-02-17 06:46:41 Etc/GMT', 'purchase_date_ms': '1581922001000', 'purchase_date_pst': '2020-02-16 22:46:41 America/Los_Angeles', 'original_purchase_date': '2020-02-17 06:46:41 Etc/GMT', 'original_purchase_date_ms': '1581922001000', 'original_purchase_date_pst': '2020-02-16 22:46:41 America/Los_Angeles', 'is_trial_period': 'false' }, { 'quantity': '1', 'product_id': 'viptest02', 'transaction_id': '1000000627734213', 'original_transaction_id': '1000000627734213', 'purchase_date': '2020-02-17 08:43:26 Etc/GMT', 'purchase_date_ms': '1581929006000', 'purchase_date_pst': '2020-02-17 00:43:26 America/Los_Angeles', 'original_purchase_date': '2020-02-17 08:43:26 Etc/GMT', 'original_purchase_date_ms': '1581929006000', 'original_purchase_date_pst': '2020-02-17 00:43:26 America/Los_Angeles', 'is_trial_period': 'false' }, { 'quantity': '1', 'product_id': 'viptest04', 'transaction_id': '1000000627684632', 'original_transaction_id': '1000000627684632', 'purchase_date': '2020-02-17 06:49:55 Etc/GMT', 'purchase_date_ms': '1581922195000', 'purchase_date_pst': '2020-02-16 22:49:55 America/Los_Angeles', 'original_purchase_date': '2020-02-17 06:49:55 Etc/GMT', 'original_purchase_date_ms': '1581922195000', 'original_purchase_date_pst': '2020-02-16 22:49:55 America/Los_Angeles', 'is_trial_period': 'false' }] }, 'status': 0, 'environment': 'Sandbox' } |
不过需要说明一点,虽然上面的方法校验了收据信息,但是不能防御中间人攻击!
原创文章,转载请注明: 转载自 obaby@mars
本文标题: 《iOS iap receipt 服务器校验》
本文链接地址: http://h4ck.org.cn/2020/02/ios-iap-receipt-%e6%9c%8d%e5%8a%a1%e5%99%a8%e6%a0%a1%e9%aa%8c/