2016-10-14 6 views
3

私の中央ゲームサーバーでGoogleのAPI経由でAndroid IAPを検証したいと考えています。AndroidのJavaサーバーサイド検証IAP

これに関する多くの部分的な情報があり、私の心を吹き飛ばしています。 Google Developerになるために25ユーロを支払ったわけではありません。なぜなら、私はそれを動作させることができるかどうかわからないからです。

IAPが作成されると、JSONオブジェクトが返されます。このオブジェクトには、purchaseTokenproductIdsource)のようないくつかのフィールドが含まれています。

次のGETリクエストで購入した商品に関する情報をリクエストできることがわかりました:GET https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/products/productId/tokens/token

私はこれを問題なくプログラムすることができますが、あなた自身を認証する必要があります。"この要求には、次の有効範囲の許可が必要です"source)。 これは私が混乱し始めたところです。

  1. デベロッパーコンソール(Link)で何らかのログイントークンを作成する必要があります。私はどんなタイプなのか分からない。 OAuthまたはサービスアカウントですか?
  2. このトークンは短命です。リフレッシュする必要があります

インターネット上で見られるいくつかの巨大なコードスニペットが機能するかもしれないし、うまくいかないかもしれませんが、それらはすべて部分的であり、あまりよく書かれていません。

Google検索のGoogleライブラリAPIライブラリ:linkが見つかりました。このAPIは、これらすべての問題をOAuthとトークンで解決するためのものです。しかし、私はこのAPIを動作させる方法を理解することができません。

おそらくそれほど難しくはありませんが、それを行う方法はたくさんあります。明確な例は見つけられません。

TL; DR: Google Play IAPサーバーサイドを確認する必要があります。これを行うには、私はGoogleのJava APIを使用したいと思います。

編集:これは簡単な解決策になるかもしれません。 オリジナルのJSONとJSONをサーバーに渡すことは、非対称の署名サーバー側を確認するだけで済むため、簡単です。

+0

これは役立ちます:https://stackoverflow.com/questions/35127086/android-inapp-purchase-receipt-validation-google-play/35138885#35138885 –

+0

私はそれに追いつこうとしましたが、そのAPI UIには完全に変更されました。また、トークンのリフレッシュの問題に対する解決策はありません。 – kwantuM

答えて

2

私はScalaでこれを行っていますが、標準のJavaライブラリを使用すると、そのコードをJavaに変換するのは簡単です。

  • まず、サービスアカウントが必要です。 Google Devコンソールから作成できます。基本的には、バックエンドサービスの認証とトークンの生成に使用する生成された電子メールを返します。

  • このアカウントを作成すると、秘密鍵をダウンロードするように求められます。あなたはJWTに署名する必要があります。

  • Googleが指定する形式でJWTを生成する必要があります。 を参照してください:https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatingjwt

  • を、その後、JWTで、あなたがアクセストークンアクセストークンで

  • を要求することができ、あなたは今、あなたの購入

    /** Generate JWT(JSON Web Token) to request access token 
        * How to generate JWT: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatingjwt 
        * 
        * If we need to generate a new Service Account in the Google Developer Console, 
        * we are going to receive a .p12 file as the private key. We need to convert it to .der. 
        * That way the standard Java library can handle that. 
        * 
        * Covert the .p12 file to .pem with the following command: 
        * openssl pkcs12 -in <FILENAME>.p12 -out <FILENAME>.pem -nodes 
        * 
        * Convert the .pem file to .der with the following command: 
        * openssl pkcs8 -topk8 -inform PEM -outform DER -in <FILENAME>.pem -out <FILENAME>.der -nocrypt 
        * 
        * */ 
        private def generateJWT(): String = { 
    
        // Generating the Header 
        val header = Json.obj("alg" -> "RS256", "typ" -> "JWT").toString() 
    
        // Generating the Claim Set 
        val currentDate = DateTime.now(DateTimeZone.UTC) 
        val claimSet =Json.obj(
         "iss" -> "<YOUR_SERVICE_ACCOUNT_EMAIL>", 
         "scope" -> "https://www.googleapis.com/auth/androidpublisher", 
         "aud" -> "https://www.googleapis.com/oauth2/v4/token", 
         "exp" -> currentDate.plusMinutes(5).getMillis/1000, 
         "iat" -> currentDate.getMillis/1000 
        ).toString() 
    
        // Base64URL encoded body 
        val encodedHeader = Base64.getEncoder.encodeToString(header.getBytes(StandardCharsets.UTF_8)) 
        val encodedClaimSet = Base64.getEncoder.encodeToString(claimSet.getBytes(StandardCharsets.UTF_8)) 
    
        // use header and claim set as input for signature in the following format: 
        // {Base64url encoded JSON header}.{Base64url encoded JSON claim set} 
        val jwtSignatureInput = s"$encodedHeader.$encodedClaimSet" 
        // use private key generated by Google Developer console to sign the content 
        val keyFile = Paths.get("<path_to_google_play_store_api.der>"); 
        val keyBytes = Files.readAllBytes(keyFile); 
    
        val keyFactory = KeyFactory.getInstance("RSA") 
        val keySpec = new PKCS8EncodedKeySpec(keyBytes) 
        val privateKey = keyFactory.generatePrivate(keySpec) 
    
        // Sign payload using the private key 
        val sign = Signature.getInstance("SHA256withRSA") 
        sign.initSign(privateKey) 
        sign.update(jwtSignatureInput.getBytes(StandardCharsets.UTF_8)) 
        val signatureByteArray = sign.sign() 
        val signature = Base64.getEncoder.encodeToString(signatureByteArray) 
    
        // Generate the JWT in the following format: 
        // {Base64url encoded JSON header}.{Base64url encoded JSON claim set}.{Base64url encoded signature} 
        s"$encodedHeader.$encodedClaimSet.$signature" 
        } 
    

検証する要求を行うことができますJWTが生成されていることを確認するには、を次のように入力します。

/** Request the Google Play access token */ 
     private def getAccessToken(): Future[String] = { 

     ws.url("https://www.googleapis.com/oauth2/v4/token") 
      .withHeaders("Content-Type" -> "application/x-www-form-urlencoded") 
      .post(
      Map(
       "grant_type" -> Seq("urn:ietf:params:oauth:grant-type:jwt-bearer"), 
       "assertion" -> Seq(generateJWT())) 
     ).map { 
      response => 
      try { 
       (response.json \ "access_token").as[String] 
      } catch { 
       case ex: Exception => throw new IllegalArgumentException("GooglePlayAPI - Invalid response: ", ex) 
      } 
     } 

     } 

アクセストークンを使用すると、購入を確認することができます。

私はそれが役立つことを願っています。

+1

努力してくれてありがとうございますが、この質問はほぼ1年前です – kwantuM

+2

あなたは正しいですが、1週間前にそれが必要でした。他人を助けるかもしれない;) –

1

上記のコメントから、Google APIマネージャーはデザインが変更されましたが、手順は同じです。 サービスアカウントを作成したい場合は、JSON Webトークンをダウンロードできます。これは、認証に必要な資格情報を持つ簡単なJSONファイルです。サービスアカウントには、Google PlayデベロッパーAPIにアクセスするために必要なすべてのアクセス権が必要です。 Google Playデベロッパーコンソール>設定> APIアクセスページでFinanceへのアクセスを許可する必要があります。

Google APIs Client Library for Javaを使用して、Google PlayデベロッパーAPIの認証とリクエストを行うことができます。 OAuth2 Service accounts文書に従って、セットアップしてください。リフレッシュトークンの処理方法を記述したData storeのメモがあります。

Google Play Developer API Client Library for Javaの使用方法に関するドキュメントもあります。

購入JSONの署名を検証する場合、購入意図の応答ペイロードにINAPP_DATA_SIGNATUREがあります。入手方法の詳細については、Purchasing an Itemのドキュメントを参照してください。 INAPP_PURCHASE_DATAをBase64で署名を復号化し、Google Playデベロッパーコンソール>すべてのアプリケーション> [アプリ名]>サービス& APIにあるライセンスキーで確認することで確認できます。 INAPP_PURCHASE_DATAがそのままであることを確認してください。さもなければ、this problemになります。

これが役に立ちます。

関連する問題