Android IAP的Java服务器端验证 [英] Java serverside verification of Android IAP

查看:46
本文介绍了Android IAP的Java服务器端验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在中央游戏服务器上通过Google API验证Android IAP.

I want to verify an Android IAP via Google's API on my central game server.

有很多关于此的部分信息,这让我大吃一惊.我还没有支付25欧元就可以成为Google开发者,因为我不确定是否能够使用它.

There is a lot of partial information about this and it is blowing my mind. I have not paid €25 to become a Google Developer, because I am not sure if I will be able to get it to work.

进行IAP时,将返回JSON对象.该对象包含几个字段,例如 purchaseToken productId (

When an IAP is made, a JSON object is returned. This object contains several fields, like the purchaseToken and the productId (source).

我发现您可以通过以下GET请求请求有关购买产品的信息: GET https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/products/productId/tokens/令牌.

I found that you can request information about a bought product via the following GET request: GET https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/products/productId/tokens/token.

我可以对此进行编程,但是您需要授权自己:此请求需要具有以下范围的授权" (

I could program this no problem, but you need to authorize yourself: "This request requires authorization with the following scope" (source). This is where I started getting confused.

  1. 您需要通过开发控制台(链接)创建某种登录令牌.我不知道是什么类型 OAuth或服务帐户?
  2. 此令牌是短暂的.您需要刷新
  1. You need to create some sort of login token via the Dev Console (Link). I don't know what type. OAuth or service account?
  2. This token is short lived. You need to refresh it

可以在互联网上找到一些巨大的代码段,这些代码段可能会或可能不会起作用,但它们都是不完整的,没有很好的文档记录.

There are several huge code snippets to be found on the internet that may or may not work, but they are all partial and not very well documented.

我找到了Java的Google API库:链接.这个API似乎是为您解决OAuth和令牌的所有这些问题.但是,我无法弄清楚如何使该API正常工作.

I found Googles API library for Java: link. This API seems to be made to fix all these problems with OAuth and tokens for you. However, I am unable to figure out how to get this API to work.

这可能并不难,但是有很多不同的方法可以做到,而我找不到任何清晰的例子.

It is probably not that hard, but there are a lot of different ways to do it, and I can't find any clear examples.

TL; DR::我需要验证Google Play IAP服务器端.为此,我想使用Google的Java API.

TL;DR: I need to verify a Google Play IAP serverside. To do this, I want to use Googles Java API.

这可能是一种更简单的解决方案.将原始JSON和JSON传递到服务器可能更容易,因为我可以验证不对称签名服务器端.

THIS MIGHT BE A WAY SIMPLER SOLUTION. Passing the original JSON plus the JSON to the server might be way easier, because I could just verify the asymmetric signature server side.

推荐答案

我已经在Scala中做到了,但是使用Java标准库.我相信将代码转换为Java应该很简单.此实现的主要优点是,它对Google库的依赖性为零.

I have done that in Scala, but using the Java standard Library. it should be simple to convert that code to Java I believe. The main advantage of this implementation is that it contains zero dependencies on Google's libraries.

  • 首先,您需要一个服务帐户.您可以通过Google Dev控制台进行创建.基本上,它会为您提供一个生成的电子邮件帐户,该帐户将用于验证后端服务并生成令牌.

  • First of all, you need a service account. You can create that via the Google Dev console. It basically gives you back a generated email account that you will use to authenticate your backend service and generate the tokens.

创建该帐户后,系统会提示您下载私钥.您需要用它来签署JWT.

With that account created, you are prompt to download your private key. You need that in order to sign the JWT.

您必须以Google指定的格式生成一个JWT(我在下面的代码中向您展示了这种方式).请参阅: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatingjwt

You have to generate a JWT in the format Google specifies (I show you how in the code below). See: https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatingjwt

然后,通过JWT,您可以请求访问令牌

then, with the JWT, you can request the access token

使用访问令牌,您可以发出请求以验证您的购买

With the access token, you can make requests to validate your purchases

/** 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 the private key generated by Google Developer console to sign the content. 
  // Maybe cache this content to avoid unnecessary round-trips to the disk.
  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,您可以像下面这样请求访问令牌:

Now that you have the JWT generated, you can ask for the access token like that:

/** 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)
      }
  }

}

有了访问令牌,您就可以自由验证购买的内容.

With the access token on your hands, you are free to validate your purchases.

我希望能帮上忙.

这篇关于Android IAP的Java服务器端验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆