Corona中文站

强大、易学的跨平台(iOS/Android)开发框架。QQ群1:74390406(满) 群2:221929599

导航

在Corona中如何对apple store的iap订单进行服务器二次验证

对于apple store中的网络应用程序,通常都需要对用户通过手机iap付费的订单,在服务器上进行二次验证,以防止用户恶意刷卡,破解app的目的。这篇文章就介绍在corona中如何来实现这一点。Apple给出的相关资料,https://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/StoreKitGuide/VerifyingStoreReceipts/VerifyingStoreReceipts.html

第一步,在corona编写的app程序代码中,用户购买产品成功后,保存apple返回的数据,并提交给服务器,参考代码如下:

function transactionCallback( event )
 local transaction = event.transaction

 if transaction.state == "purchased" then
  --native.showAlert("提示", "购买成功,等待服务器验证。", {"OK"})
  print("Transaction succuessful!")
  print("productIdentifier", transaction.productIdentifier)
  print("receipt", transaction.receipt)
  print("transactionIdentifier", transaction.identifier)
  print("date", transaction.date)
  check(transaction.receipt) --向服务器提交这个数据
 elseif  transaction.state == "restored" then
 elseif transaction.state == "cancelled" then elseif transaction.state == "failed" then else
  print("unknown event")
 end

 store.finishTransaction( transaction )end

corona提交的数据样本:

<7b0a0922 7369676e 61747572 6522203d 2022416d 5059576d 54787946 68416d52 63385233 71465171 78746870 6d416638 46343543 435a676a 72535a57 68445775 71555956 514a6279 39786c79 4d4f4c65 764d425a 66514339 41727941 716d6e69 736a7a37 36696a59 2b43564b 4b394637 774b5831 7232484c 4e732b59 4a2f2b70 70553948 67693961 574d4761 6a303773 506c7758 47476e4d 78776d30 4e336d65 47667235 31784465 70512b4f 514f6b41 764e467a 6b674448 33314e39 7a574141 4144567a 43434131 4d776767 49376f41 4d434151 49434347 55556b55 335a5741 53314d41 30474353 71475349 62334451 45424251 55414d48 3878437a 414a4267 4e564241 5954416c 56544d52 4d774551 59445651 514b4441 70426348 42735a53 424a626d 4d754d53 59774a41 59445651 514c4442 31426348 42735a53 42445a58 4a306157 5a705932 46306157 39754945 46316447 6876636d 6c306554 457a4d44 45474131 55454177 77715158 42776247 55676156 5231626d 567a4946 4e306233 4a6c4945 4e6c636e 52705a6d 6c6a5958 52706232 34675158 56306147 39796158 52354d42 34584454 41354d44 59784e54 49794d44 55314e6c 6f584454 45304d44 59784e44 49794d44 55314e6c 6f775a44 456a4d43 45474131 55454177 77615548 56795932 68686332 56535a57 4e6c6158 42305132 56796447 6c6d6157 4e686447 5578477a 415a4267 4e564241 734d456b 46776347 786c4947 6c556457 356c6379 42546447 39795a54 45544d42 45474131 55454367 774b5158 42776247 55675357 356a4c6a 454c4d41 6b474131 55454268 4d435656 4d77675a 38774451 594a4b6f 5a496876 634e4151 45424251 41446759 30414d49 474a416f 4742414d 72526a46 32637434 49725364 69544368 61493067 38707776 2f636d48 7338702f 5277562f 72742f39 31584b56 684e6c34 58494269 6d4b6a51 514e6667 48734473 36796a75 2b2b4472 4b4a4537 754b7370 684d6464 4b596646 45357247 58734164 42456a42 77524978 65785465 76783348 4c454647 4174316d 6f4b7835 30396468 78746949 6444674a 76325961 56733439 4230754a 764e6479 36534d71 4e4e4c48 73444c7a 4453396f 5a484167 4d424141 476a636a 42774d41 77474131 55644577 45422f77 51434d41 41774877 59445652 306a4242 6777466f 41554e68 336f3470 32433067 45597454 4a724474 64444335 4659517a 6f774467 59445652 30504151 482f4241 51444167 65414d42 30474131 55644467 51574242 53706734 50794755 6a465068 4a584342 544d7a61 4e2b6d56 386b3954 41514267 6f71686b 69473932 4e6b4267 55424241 49464144 414e4267 6b71686b 69473977 30424151 55464141 4f434151 45414561 5362506a 746d4e34 432f4942 33514570 4b333252 78616343 44586456 58416556 52655335 46615a78 632b7438 38705150 39334269 41787664 572f3365 54534d47 59354662 6541594c 33657471 5035676d 38777246 6f6a5830 696b7956 52537451 2b2f4151 304b456a 74714230 376b4c73 39515565 38637a52 38554766 644d3145 756d562f 55677644 64344e77 4e59784c 514d6734 57545166 676b5151 56793847 585a7756 48676245 2f554336 59373035 33704758 426b3531 4e504d33 776f7868 64336753 524c7658 6a2b6c6f 48735374 63544571 65397042 44706d47 352b736b 3474772b 474b3347 4d65454e 352f2b65 31515439 6e702f4b 6c316e6a 2b614277 37433078 73793062 466e6141 64316353 53367864 6f72792f 4355764d 3667744b 736d6e4f 4f647154 65736270 30627338 736e3657 71733043 39646763 78524875 4f4d5a32 746d386e 704c556d 37617267 4f537a51 3d3d223b 0a092270 75726368 6173652d 696e666f 22203d20 2265776f 4a496d39 79615764 70626d46 734c5842 31636d4e 6f59584e 6c4c5752 68644755 7463484e 30496941 39494349 794d4445 794c5441 794c5445 30494441 784f6a49 354f6a51 31494546 745a584a 70593245 76544739 7a583046 755a3256 735a584d 694f776f 4a496d39 79615764 70626d46 734c5852 79595735 7a59574e 30615739 754c576c 6b496941 39494349 784d4441 774d4441 774d4449 324e7a4d 334e6a55 30496a73 4b43534a 69646e4a 7a496941 39494349 784c6a41 694f776f 4a496e52 79595735 7a59574e 30615739 754c576c 6b496941 39494349 784d4441 774d4441 774d4449 324e7a4d 334e6a55 30496a73 4b43534a 78645746 7564476c 30655349 67505341 694d5349 3743676b 6962334a 705a326c 75595777 74634856 79593268 68633255 745a4746 305a5331 74637949 67505341 694d544d 794f5449 784d5463 344e5463 314e6949 3743676b 6963484a 765a4856 6a644331 705a4349 67505341 6962336c 6c4c6d64 68625756 7a4c6d6c 68634335 35645746 75596d46 76496a73 4b43534a 70644756 744c576c 6b496941 39494349 314d4449 304e544d 314d7a59 694f776f 4a496d4a 705a4349 67505341 6962336c 6c4c6d64 68625756 7a4c6d6c 68634852 6c633351 694f776f 4a496e42 31636d4e 6f59584e 6c4c5752 68644755 7462584d 69494430 67496a45 7a4d6a6b 794d5445 334f4455 334e5459 694f776f 4a496e42 31636d4e 6f59584e 6c4c5752 68644755 69494430 67496a49 774d5449 744d4449 744d5451 674d446b 364d6a6b 364e4455 67525852 6a4c3064 4e564349 3743676b 69634856 79593268 68633255 745a4746 305a5331 77633351 69494430 67496a49 774d5449 744d4449 744d5451 674d4445 364d6a6b 364e4455 67515731 6c636d6c 6a595339 4d62334e 66515735 6e5a5778 6c637949 3743676b 6962334a 705a326c 75595777 74634856 79593268 68633255 745a4746 305a5349 67505341 694d6a41 784d6930 774d6930 784e4341 774f546f 794f546f 304e5342 4664474d 76523031 55496a73 4b66513d 3d223b0a 0922656e 7669726f 6e6d656e 7422203d 20225361 6e64626f 78223b0a 0922706f 6422203d 20223130 30223b0a 09227369 676e696e 672d7374 61747573 22203d20 2230223b 0a7d>

第二步,在服务器对客户端提交的订单数据,向苹果进行订单合法性验证。注意:这里要对corona提交的数据进行解码,并进行base64加密。

 c#中进行解码的代码:

//解密及base64加密过程

        private string DecodeReceipt(string receipt)
        {
            string postDataStr = "";
            try
            {
                receipt = Regex.Replace(receipt, @"[^0-9a-fA-F]", "");
                string ret = "";
                for (int i = 0; i < receipt.Length; i = i + 2)
                {
                    string tmp = receipt.Substring(i, 2);
                    byte b = byte.Parse(tmp, System.Globalization.NumberStyles.HexNumber);
                    char ch = Convert.ToChar(b);
                    ret += ch;
                }
                byte[] bytes = Encoding.Default.GetBytes(ret);
                postDataStr = "{\"receipt-data\":\"" + Convert.ToBase64String(bytes) + "\"}";
            }
            catch
            {
            }
            return postDataStr;
        }

        //进行验证

                string postDataStr = DecodeReceipt(Request.Form("receipt"));

                //提交服务器
                HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://sandbox.itunes.apple.com/verifyReceipt");//https://buy.itunes.apple.com/verifyReceipt
                request.Method = "POST";
                request.ContentType = "application/x-www-form-urlencoded";
                request.ContentLength = postDataStr.Length;
                Stream myRequestStream = request.GetRequestStream();
                StreamWriter myStreamWriter = new StreamWriter(myRequestStream, Encoding.GetEncoding("gb2312"));
                myStreamWriter.Write(postDataStr);
                myStreamWriter.Close();

                HttpWebResponse response = (HttpWebResponse)request.GetResponse();
                Stream myResponseStream = response.GetResponseStream();
                StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
                string retString = myStreamReader.ReadToEnd();
                myStreamReader.Close();
                myResponseStream.Close();

                Response.Write(retString);
 

php中进行解码并提交验证的例子:

<?php  
   function getReceiptData($receipt, $isSandbox = false)  
   {  
       if ($isSandbox) {  
           $endpoint = 'https://sandbox.itunes.apple.com/verifyReceipt';  
       }  
       else {  
           $endpoint = 'https://buy.itunes.apple.com/verifyReceipt';  
       }  
   
        $postData = json_encode(  
            array('receipt-data' => base64_encode($receipt))  
        );  
   
        $ch = curl_init();    
        $timeout = 300; // set to zero for no timeout
        curl_setopt($ch, CURLOPT_URL, $endpoint);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); //post到https
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);//跟随页面的跳转
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);

        $response = curl_exec($ch);  
        $errno    = curl_errno($ch);  
        $errmsg   = curl_error($ch);  
        curl_close($ch);  
   
        if ($errno != 0) {  
            throw new Exception($errmsg, $errno);  
        }   
          echo($postData);
          echo("\r\n\r\n");
          echo($response);
        $data = json_decode($response);  
   
        if (!is_object($data)) {  
            throw new Exception('Invalid response data');  
        }  
   
        if (!isset($data->status) || $data->status != 0) {  
            throw new Exception('Invalid receipt');  
        }  
   
        return array(  
            'quantity'       =>  $data->receipt->quantity,  
            'product_id'     =>  $data->receipt->product_id,  
            'transaction_id' =>  $data->receipt->transaction_id,  
            'purchase_date'  =>  $data->receipt->purchase_date,  
            'app_item_id'    =>  $data->receipt->app_item_id,  
            'bid'            =>  $data->receipt->bid,  
            'bvrs'           =>  $data->receipt->bvrs  
        );  
    }  
   
    $receipt   = $_REQUEST['receipt'];  
    $isSandbox = (bool) $_REQUEST['sandbox'];  
   
    try {   
  $hex = $receipt
  $temp = preg_replace("/[^0-9a-fA-F]/","", $hex);
  for($i = 0; $i < strlen($temp); $i = $i + 2)
  {
   $ascii = $ascii.chr(hexdec(substr($temp, $i, 2)));
  }
  //以上是对corona提交的数据进行解密

        $info = getReceiptData($ascii, true);  
        //验证购买有效  
    }  
    catch (Exception $ex) {  
        //验证购买无效 
  echo($ex);
    }  
?> 

提交的数据样本:

==================提交给Apple store的JSON串==================
{"receipt-data":"ewoJInNpZ25hdHVyZSIgPSAiQWh0dWJkTWJ3ZUJ2UjA1V2paNTVaUWczcWxOOUFLNUhHNWNjSjJHdWFOOG9BZ1pxc2FwMTllSlRsZmRYKzh4SHFMSTJKSjRFditYWWZBemZvN1pPczVobTh4bVVhNXAxZ2FnWSsvaXJEU1QwdUcyYWo5VjdvYksvczk0L0Q4dGk1dThIZ3dKcHJMU1E2dG5YT2JNRXVkUi9FVjU1WThMSzI5REYzeVV0MDJEMEFBQURWekNDQTFNd2dnSTdvQU1DQVFJQ0NHVVVrVTNaV0FTMU1BMEdDU3FHU0liM0RRRUJCUVVBTUg4eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURXpNREVHQTFVRUF3d3FRWEJ3YkdVZ2FWUjFibVZ6SUZOMGIzSmxJRU5sY25ScFptbGpZWFJwYjI0Z1FYVjBhRzl5YVhSNU1CNFhEVEE1TURZeE5USXlNRFUxTmxvWERURTBNRFl4TkRJeU1EVTFObG93WkRFak1DRUdBMVVFQXd3YVVIVnlZMmhoYzJWU1pXTmxhWEIwUTJWeWRHbG1hV05oZEdVeEd6QVpCZ05WQkFzTUVrRndjR3hsSUdsVWRXNWxjeUJUZEc5eVpURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd2daOHdEUVlKS29aSWh2Y05BUUVCQlFBRGdZMEFNSUdKQW9HQkFNclJqRjJjdDRJclNkaVRDaGFJMGc4cHd2L2NtSHM4cC9Sd1YvcnQvOTFYS1ZoTmw0WElCaW1LalFRTmZnSHNEczZ5anUrK0RyS0pFN3VLc3BoTWRkS1lmRkU1ckdYc0FkQkVqQndSSXhleFRldngzSExFRkdBdDFtb0t4NTA5ZGh4dGlJZERnSnYyWWFWczQ5QjB1SnZOZHk2U01xTk5MSHNETHpEUzlvWkhBZ01CQUFHamNqQndNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVOaDNvNHAyQzBnRVl0VEpyRHRkREM1RllRem93RGdZRFZSMFBBUUgvQkFRREFnZUFNQjBHQTFVZERnUVdCQlNwZzRQeUdVakZQaEpYQ0JUTXphTittVjhrOVRBUUJnb3Foa2lHOTJOa0JnVUJCQUlGQURBTkJna3Foa2lHOXcwQkFRVUZBQU9DQVFFQUVhU2JQanRtTjRDL0lCM1FFcEszMlJ4YWNDRFhkVlhBZVZSZVM1RmFaeGMrdDg4cFFQOTNCaUF4dmRXLzNlVFNNR1k1RmJlQVlMM2V0cVA1Z204d3JGb2pYMGlreVZSU3RRKy9BUTBLRWp0cUIwN2tMczlRVWU4Y3pSOFVHZmRNMUV1bVYvVWd2RGQ0TndOWXhMUU1nNFdUUWZna1FRVnk4R1had1ZIZ2JFL1VDNlk3MDUzcEdYQms1MU5QTTN3b3hoZDNnU1JMdlhqK2xvSHNTdGNURXFlOXBCRHBtRzUrc2s0dHcrR0szR01lRU41LytlMVFUOW5wL0tsMW5qK2FCdzdDMHhzeTBiRm5hQWQxY1NTNnhkb3J5L0NVdk02Z3RLc21uT09kcVRlc2JwMGJzOHNuNldxczBDOWRnY3hSSHVPTVoydG04bnBMVW03YXJnT1N6UT09IjsKCSJwdXJjaGFzZS1pbmZvIiA9ICJld29KSW05eWFXZHBibUZzTFhCMWNtTm9ZWE5sTFdSaGRHVXRjSE4wSWlBOUlDSXlNREV5TFRBeUxURXpJREU1T2pJME9qVXlJRUZ0WlhKcFkyRXZURzl6WDBGdVoyVnNaWE1pT3dvSkltOXlhV2RwYm1Gc0xYUnlZVzV6WVdOMGFXOXVMV2xrSWlBOUlDSXhNREF3TURBd01ESTJOamM0TWpVeUlqc0tDU0ppZG5KeklpQTlJQ0l4TGpBaU93b0pJblJ5WVc1ellXTjBhVzl1TFdsa0lpQTlJQ0l4TURBd01EQXdNREkyTmpjNE1qVXlJanNLQ1NKeGRXRnVkR2wwZVNJZ1BTQWlNU0k3Q2draWIzSnBaMmx1WVd3dGNIVnlZMmhoYzJVdFpHRjBaUzF0Y3lJZ1BTQWlNVE15T1RFNE9UZzVNakU1TVNJN0Nna2ljSEp2WkhWamRDMXBaQ0lnUFNBaWIzbGxMbWRoYldWekxuaHBZVzl4YVdGdWEzVmhhWEJoYnk1b2NIQnNkWE14SWpzS0NTSnBkR1Z0TFdsa0lpQTlJQ0kxTURJME1qa3dPVGNpT3dvSkltSnBaQ0lnUFNBaWIzbGxMbWRoYldWekxuaHBZVzl4YVdGdWEzVmhhWEJoYnlJN0Nna2ljSFZ5WTJoaGMyVXRaR0YwWlMxdGN5SWdQU0FpTVRNeU9URTRPVGc1TWpFNU1TSTdDZ2tpY0hWeVkyaGhjMlV0WkdGMFpTSWdQU0FpTWpBeE1pMHdNaTB4TkNBd016b3lORG8xTWlCRmRHTXZSMDFVSWpzS0NTSndkWEpqYUdGelpTMWtZWFJsTFhCemRDSWdQU0FpTWpBeE1pMHdNaTB4TXlBeE9Ub3lORG8xTWlCQmJXVnlhV05oTDB4dmMxOUJibWRsYkdWeklqc0tDU0p2Y21sbmFXNWhiQzF3ZFhKamFHRnpaUzFrWVhSbElpQTlJQ0l5TURFeUxUQXlMVEUwSURBek9qSTBPalV5SUVWMFl5OUhUVlFpT3dwOSI7CgkiZW52aXJvbm1lbnQiID0gIlNhbmRib3giOwoJInBvZCIgPSAiMTAwIjsKCSJzaWduaW5nLXN0YXR1cyIgPSAiMCI7Cn0="}

第三步,对apple返回的数据进行处理

==================Appl store返回的验证结果(正常的订单)==================
{"receipt":{"original_purchase_date_pst":"2012-02-13 19:24:52 America/Los_Angeles", "original_transaction_id":"1000000026678252", "original_purchase_date_ms":"1329189892191", "transaction_id":"1000000026678252", "quantity":"1", "product_id":"oye.games.xiaoqiankuaipao.hpplus1", "bvrs":"1.0", "purchase_date_ms":"1329189892191", "purchase_date":"2012-02-14 03:24:52 Etc/GMT", "original_purchase_date":"2012-02-14 03:24:52 Etc/GMT", "purchase_date_pst":"2012-02-13 19:24:52 America/Los_Angeles", "bid":"oye.games.xiaoqiankuaipao", "item_id":"502429097"}, "status":0}

==================Appl store返回的验证结果(无效的订单)==================
{"status":21002, "exception":"java.lang.NullPointerException"}
//status为非0值,则表示收据无效

<< lua中如何对字符串进行Base64加密apple store应用程序iap防破解的补充说明 >>

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

最近发表

Powered By Z-Blog 1.8 Walle Build 100427 Copyright 2011-2015 BuildApp.Net. All Rights Reserved.