最近公司要做海外版,需要接入google play.踩了不少坑,特作此文
20180809更新,增加导包,参数示例数据
验证方法1 rsa签名验证
请参考这篇
验证方法2 请求google api验证
需要在google developer console申请service account,具体参考这篇
我的做法 我比较diao,两种都上了(手动滑稽)
其实是因为之前我认为publicKey在客户端也存在,可能有风险,真正明白后才知道rsa的公匙本来就是可以可以公开的,私匙是有google有,肯定是安全的,但是代码已经上线了,也浪费不了多少资源,算是双重保险吧
放码过来
maven依赖
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-androidpublisher</artifactId>
<version>v2-rev44-1.22.0</version>
</dependency>
充值接口,在这里进行充值操作
public Map<String, Object> vertifyOrder(
@RequestParam("purchaseData") String purchaseData,
@RequestParam("signature") String signature,
@RequestParam("type") int type) {
拦截器,通过后的请求才会调用充值接口.key.p12文件是在classpath下
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Collections;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.SecurityUtils;
import com.google.api.services.androidpublisher.AndroidPublisher;
import com.google.api.services.androidpublisher.AndroidPublisherScopes;
import com.google.api.services.androidpublisher.model.ProductPurchase;
/**
* @author weilong.wang Created on 2017/12/8
*/
@Aspect
@Component
public class GoogleSignInterceptor {
private static final Logger logger = LoggerManage.getLogger();
private static final String SERVICE_ACCOUNT_EMAIL = "{googlePlay.serviceAccountEmail}";
private static final String PUBLIC_KEY = "{googlePlay.publicKey}";
private static final String P12_Key = "/key.p12";
@Around("execution(* xxx.xxx.xxx.vertifyOrder (..))")
public Object preHandle(ProceedingJoinPoint proceedingJoinPoint) {
Object[] args = proceedingJoinPoint.getArgs();
// 获取参数
String signature = null;
String purchaseData = null;
try {
purchaseData = String.valueOf(args[0]);
signature = String.valueOf(args[1]);
} catch (NullPointerException e) {
logger.error("参数为空");
}
// 签名校验
String publicKey = ConfigManager.getProperty(PUBLIC_KEY);
try {
boolean isVertify = docheck(purchaseData, signature, publicKey);
if (isVertify == false) {
logger.error("签名校验失败publicKey:" + publicKey);
}
} catch (Exception e) {
logger.error("签名校验失败", e);
}
// 调用google api二次校验
com.alibaba.fastjson.JSONObject jsonObject;
try {
jsonObject = JSON.parseObject(purchaseData);
} catch (JSONException e) {
logger.error("purchaseData解析失败", e);
}
String productId = jsonObject.getString("productId");
String packageName = jsonObject.getString("packageName");
String purchaseToken = jsonObject.getString("purchaseToken");
int purchaseState = jsonObject.getIntValue("purchaseState");
if (purchaseState != 0) {
logger.error("订单未支付!");
}
try {
HttpTransport transport = GoogleNetHttpTransport
.newTrustedTransport();
PrivateKey privateKey = SecurityUtils.loadPrivateKeyFromKeyStore(
SecurityUtils.getPkcs12KeyStore(),
this.getClass().getResourceAsStream(P12_Key), "notasecret",
"privatekey", "notasecret");
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(transport)
.setJsonFactory(JacksonFactory.getDefaultInstance())
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(Collections
.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
.setServiceAccountPrivateKey(privateKey).build();
AndroidPublisher publisher = new AndroidPublisher.Builder(transport,
JacksonFactory.getDefaultInstance(), credential).build();
AndroidPublisher.Purchases.Products products = publisher.purchases()
.products();
AndroidPublisher.Purchases.Products.Get product = products
.get(packageName, productId, purchaseToken);
ProductPurchase purchase = product.execute();
if (purchase.getPurchaseState() != 0) {
logger.error("订单未支付!");
}
} catch (Exception e) {
logger.error("订单验证失败! ", e);
}
try {
return proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
logger.error("系统错误", throwable);
}
}
private boolean docheck(String content, String sign, String publicKey)
throws Exception {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] encodedKey = Base64.getDecoder().decode(publicKey);
PublicKey pubKey = keyFactory
.generatePublic(new X509EncodedKeySpec(encodedKey));
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes("utf-8"));
return signature.verify(Base64.getDecoder().decode(sign));
}
}
前端传递的参数,仅供参考,隐私信息已去除
purchaseData={"orderId":"GPA.3330-4532-0035-01959","packageName":"{packageName}","productId":"{productName}","purchaseTime":1533737586295,"purchaseState":0,"developerPayload":"9c97bb8c-1320-4088-a9c8-6ead08325655{productName}","purchaseToken":"hcgakhnoeoiikhjicdlobfkm.AO-J1OykrKdrP6OFvIvNN3P_ZPOP8IlJSqIO95fiDYhWpB8hN6_PX23XtsEjNg8y5-pCM5AjCp8lZ_daGTQOS9HGS20xA7ev3DEqwl5_HQDnvIGTlrr_divZaA8F6zYTkF3lngn2n11j5DswMyqq84Cz6v2JlKwGWg"}&signature=fP3liv/tbrw0PUgQA/iCymOL1l56wBY8bLgqK58ktcIHGgai166ijpg9jbx3QvJ9ljgmwJca/7N/n6jzzADTy49rtpY2sNvaZDrHcwVLXXfRT9tPgMi2NgTGfRGgNw7lwXH9TkewU7rSJmeDznnuEpf8cfO24FgoUi61XZEPFrz8G83O94nQvNUgIirXQZneKmRGYWrZcomuaHmAVP3CtEchvO0AjlhDsbvZIePfkfPOAgR5PWNgwo0YpNS0TZzSErdPCDgJMxRyztisuqQnExSXnjnGtUQDSk4Ohdu4sIoeLDez8gC30yJ+g8dAtuwLw5L+yxXsEYnX7ALZk950Xg==&type=1
网友评论