Server-side verification of Google Play In-app billing version 3 purchase

后端 未结 5 1708
滥情空心
滥情空心 2020-12-01 00:09

I\'m unable to find a straight answer as to how I verify an in-app billing purchase on the server before making downloadable content available to the user.

I use in

相关标签:
5条回答
  • 2020-12-01 00:36
    where do I get the signature from ?
    

    Have a look at official docs,

    It says that inside your onActivityResult() method you can get following data as shown in example,

        @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
       if (requestCode == 1001) {           
          int responseCode = data.getIntExtra("RESPONSE_CODE", 0);
          String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA");
          String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE");//this is the signature which you want
    
          if (resultCode == RESULT_OK) {
             try {
                JSONObject jo = new JSONObject(purchaseData);//this is the JSONObject which you have included in Your Question right now
                String sku = jo.getString("productId");
                String purchaseToken = jo.getString("purchaseToken");
               //you need to send sku and purchaseToken to server for verification
              }
              catch (JSONException e) {
                 alert("Failed to parse purchase data.");
                 e.printStackTrace();
              }
          }
       }
    }
    

    For verification on server end, Have a look at official docs

    As mentioned earlier, client app will send sku and purchaseToken to server API. Server will have to receive those values and will have to perform check with android publish api to verify purchase:

    Server may call following GET request by adding necessary parameters:

    https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/products/productId/tokens/token

    here,
    packageName = packageName of the client app
    productId = sku received from client app
    token = purchaseToken received from client app

    It will result into a JSONObject response as mentioned format:

    {
      "kind": "androidpublisher#productPurchase",
      "purchaseTimeMillis": long,
      "purchaseState": integer,
      "consumptionState": integer,
      "developerPayload": string,
      "orderId": string,
      "purchaseType": integer
    }
    

    here, purchaseState = 0 means valid purchase

    I hope it will be helpful !!

    0 讨论(0)
  • 2020-12-01 00:39

    My small contribution to reduce fraud in in-app purchases

    Signature verification on an external server, on your Android code :

    verifySignatureOnServer()

      private boolean verifySignatureOnServer(String data, String signature) {
            String retFromServer = "";
            URL url;
            HttpsURLConnection urlConnection = null;
            try {
                String urlStr = "https://www.example.com/verify.php?data=" + URLEncoder.encode(data, "UTF-8") + "&signature=" + URLEncoder.encode(signature, "UTF-8");
    
                url = new URL(urlStr);
                urlConnection = (HttpsURLConnection) url.openConnection();
                InputStream in = urlConnection.getInputStream();
                InputStreamReader inRead = new InputStreamReader(in);
                retFromServer = convertStreamToString(inRead);
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
            }
    
            return retFromServer.equals("good");
        }
    

    convertStreamToString()

     private static String convertStreamToString(java.io.InputStreamReader is) {
            java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A");
            return s.hasNext() ? s.next() : "";
        }
    

    verify.php on the root directory of web hosting

    <?php
    // get data param
    $data = $_GET['data'];
    
    // get signature param
    $signature = $_GET['signature'];
    
    // get key
    $key_64 = ".... put here the base64 encoded pub key from google play console , all in one row !! ....";
    
    
    
    $key =  "-----BEGIN PUBLIC KEY-----\n".
            chunk_split($key_64, 64,"\n").
           '-----END PUBLIC KEY-----';   
    //using PHP to create an RSA key
    $key = openssl_get_publickey($key);
    
    
    // state whether signature is okay or not
    $ok = openssl_verify($data, base64_decode($signature), $key, OPENSSL_ALGO_SHA1);
    if ($ok == 1) {
        echo "good";
    } elseif ($ok == 0) {
        echo "bad";
    } else {
        die ("fault, error checking signature");
    }
    
    // free the key from memory
    openssl_free_key($key);
    
    ?>
    

    NOTES:

    • You should encrypt the URL in your java code, if not the URL can be found easy with a simple text search in your decompressed app apk

    • Also better to change php file name, url arguments, good/bad reponses to something with no sense.

    • verifySignatureOnServer() should be run in a separated thread if not a network on main thread exception will be thrown.

    Hope it will help ...

    0 讨论(0)
  • 2020-12-01 00:46

    1.Install Google client PHP libary with composer

    composer require google/apiclient:"^2.0"
    
    1. Create service account and it will give you json and saved as credentials.json

    1. start code

      require $_SERVER['DOCUMENT_ROOT'] . '/client/vendor/autoload.php';
      
      $packageName='Your Package name'; //com.example.blahblah
      $productId='your_product_ID';
      $token='Purchase_Token_Form_Payment';
      
      $client = new \Google_Client();
      $client->setAuthConfig('credentials.json');
      $client->addScope('https://www.googleapis.com/auth/androidpublisher');
      
      $service = new \Google_Service_AndroidPublisher($client);
      $purchase = $service->purchases_products->get($packageName, $productId, $token);
      
      //echo $purchase['purchaseState'];
      //echo '<br>';
      echo json_encode($purchase);
      

    result will be like this

    {"acknowledgementState":1,"consumptionState":1,"developerPayload":"","kind":"androidpublisher#productPurchase","orderId":"GPA.3342-8146-5668-57982","productId":null,"purchaseState":0,"purchaseTimeMillis":"1586978561493","purchaseToken":null,"purchaseType":0,"quantity":null}
    
    0 讨论(0)
  • 2020-12-01 00:47

    This is too old question, but I hope my answer can help somebody.

    You have to validate signature on client side, and then you have to pass purchaseToken to server side, and then server will contact Google's server and get all necessary information about purchase, such as purchaseState and consumptionState.

    https://developers.google.com/android-publisher/api-ref/purchases/products

    0 讨论(0)
  • 2020-12-01 00:55

    This is very old question but I think it is still relevant.

    My small contribution. Purchase object is extended for one new parameter "acknowledged" and now it looks:

    {
      "orderId":"12999763169054705758.1364365967744519",
      "packageName":"my package name",
      "productId":"77",
      "purchaseTime":1366217534000,
      "purchaseState":0,
      "purchaseToken":"utfwimslnrrwvglktizikdcd.AO-J1OwZ4l5oXz_3d2SAWAAUgFE3QErKoyIX8WuSEnBW26ntsyDmlLgoUd5lshqIY2p2LnlV4tpH4NITB4mJMX98sCtZizH7wGf6Izw3tfW_GflJDKFyb-g",
      "acknowledged":true
    }
    

    So be careful when check signature to add this one extra parameter.

    0 讨论(0)
提交回复
热议问题