服务端验证Google Pay订单的两种方式

Google Pay主要支付流程:

1.手机端向服务端发起支付,生成预订单,给手机端返回生成的订单号

2.手机端向Google发起支付(传入本地服务器生成的订单号)

3.Google服务器将支付结果返回给手机端(因这边用到的是消耗型的产品,所以购买后必须要通知gp我已经消耗了这次交易)

4.手机端向服务端发送校验请求,校验通过后即可处理订单(服务端重试校验,发货,保证订单正常发货成功)
 

当客户端支付成功后,客户端将支付订单的token 传给服务端,服务端进行再次校验,服务端校验订单有两种方式:

1.引入google apis 调取Google Api 进行验证 

2.直接调用Google 提供的API接口去验证

两种验证方式都需要一些配置和相应参数,下面具体讲解

验证方式 一 : 引入google apis 调取Google Api 进行验证 

developer文档地址:https://developers.google.com/identity/protocols/oauth2/service-account?hl=zh-cn#delegatingauthority

  1.去Google Play Console 选择设置中的API 权限:https://play.google.com/console/u/0/developers/6365974680746954105/api-access

  

2.第一次进来没有 Google Play Console Developer,这个时候就需要去Google Cloud Platform 后台创建服务账号.首先去Google Cloud 后台https://console.cloud.google.com/ 搜索:Google Play Console Developer 点击启用即可,然后去创建服务账号:

 

 

 到这里就把Google Play Console Developer创建好了,最后一步也拿到了对应的json了

3.回到Google Play Console 后台 把刚才创建的Google Play Console Developer的服务账号也加入到用户和权限中

然后将服务账号权限,可以直接给管理员admin permission 也可以给 财务权限:

 点击API权限中的 查看Play管理中心权限,可以查看应用权限和账号权限,切记要给与对应Project的permission

 4.上面三步Google Play Console Developer的环境配置好了,下面就开始实现服务端订单的校验了,Java服务端处理

首先将google apis 接入到项目:

<project>
  <dependencies>
    <dependency>
      <groupId>com.google.apis</groupId>
      <artifactId>google-api-services-androidpublisher</artifactId>
      <version>v3-rev20211125-1.32.1</version>
    </dependency>
  </dependencies>
</project>

校验代码:

@RestController
public class GoogleController {
 
    //	packageName为应用程序包名、productId商品id、purchaseToken谷歌返回的收据
    @PostMapping("/")
    public ProductPurchase checkOrder(@RequestBody GooglePayDto googlePayDto,
                              HttpServletRequest requestDto) throws IOException, GeneralSecurityException {
        //使用服务帐户Json文件获取Google凭据
        List<String> scopes = new ArrayList<>();
        scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        Resource resource = resourceLoader.getResource("classpath:static/刚下载的json文件,这里放到了static目录下");
        GoogleCredential credential = GoogleCredential.fromStream(resource.getInputStream())
                .createScoped(scopes);
//        使用谷歌凭据和收据从谷歌获取购买信息
        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        JacksonFactory jsonFactory = new JacksonFactory();
        AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential)
                .setApplicationName("应用程序名").build();
        AndroidPublisher.Purchases purchases = publisher.purchases();
        final AndroidPublisher.Purchases.Products.Get request = purchases.products().get(googlePayDto.getPackageName(), googlePayDto.getProductId(),googlePayDto.getPurchaseToken());
        System.out.println("==============="+request+"================");
        final ProductPurchase purchase = request.execute();
        //处理业务
        Integer purchaseState = purchase.getPurchaseState();
        if (!GooglePayStatus.PURCHASED.getValue().equals(purchaseState) &&!GoogleConsumptionStatus.YET_TO_BE_CONSUMED.getValue().equals(purchase.getConsumptionState())) {
            log.info("==========>订单校验【成功】");
        } else {
            log.info("==========>订单校验【失败】");
        }
        return purchase;
    }
}
public class GooglePayDto {
 
    String packageName;
    String productId;
    String purchaseToken;
 
    public String getPackageName() {
        return packageName;
    }
 
    public void setPackageName(String packageName) {
        this.packageName = packageName;
    }
 
    public String getProductId() {
        return productId;
    }
 
    public void setProductId(String productId) {
        this.productId = productId;
    }
 
    public String getPurchaseToken() {
        return purchaseToken;
    }
 
    public void setPurchaseToken(String purchaseToken) {
        this.purchaseToken = purchaseToken;
    }
}

最后开始Test:

传入三个参数

packageName:包名

productId:商品id

purchaseToken:支付凭证

运行结果:

 验证方式 二 : 使用API接口直接验证,developer文档地址:https://developers.google.com/android-publisher/authorization?hl=zh-cn

整体步骤:

  1. 创建api项目这个和登录用的项目不是同一个

  2. 开启Google Play Android Developer API

  3. 设置oauth同意屏幕(就是拉起开发者授权账号登录时的登录页面)

  4. 创建web应用的oauth客户端ID

  5. google play开发者后台,API权限菜单中关联刚刚创建的项目,一个google play账号只需要也只能关联一个api项目就行了,这个项目可以查询关联账号中的所有应用的订单

  6. 拉起授权页面,使用google开发者账号给项目授权,得到code

  7. 通过code,拿到refreshToken,这个token只有第一次才会返回需要永久储存(这个refreshtoken很重要,需要保存下来),如果弄丢,只有重新创建一个oauth客户端ID,然后重复步骤6,7,拿到新的refreshtoken

  8. 刷新refreshToken, 得到accessToken,通过accesstoken就可以去查询订单状态了,这里的accessToken一般只有5分钟左右,5分钟后需要重新用refreshToken换取新的accessToken

详细步骤:setp1:

创建api项目google api console

 setp2:开启Google Play Android Developer API

搜索“Google Play Android Developer API”,并开启

setp3:开启OAuth同意屏幕

setp4 :  创建OAuth 客户端ID:

创建页面和创建成功后的修改页面可以获取到clientId和clientSecret:

到这里api项目就已经创建好了 

setp5: Google Play 后台关联API项目:

setp6:获取code

地址:https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri={填写的重定向地址}&client_id={创建的clientId}

将上面的{XX}替换成创建api项目时填写的重定向地址,和clientId,然后将连接放到浏览器中打开,就会吊起授权界面,使用你的开发者账号授权登录

请求方式:浏览器中打开 授权,URL会重定向,这个时候可以拿到code:

这里可以看到,重定向地址上有两个参数code和scope,我们只需要code就行了,这里的code是urlencode后的,使用时需要decode

setp7:使用code获取refreshToken 这一步可以用Postman发起一个post请求:

url:https://accounts.google.com/o/oauth2/token

请求方式:post

参数:grant_type=authorization_code

code=获取到的code(需要看看code中是否有%号,如果有需要urldecode)

client_id=创建api项目是的clientId(客户端ID)

client_secret=创建api项目时的clientSecret(客户端密钥)

redirect_uri=创建api项目时的重定向地址

 

这里就获取到refreshToken了,重点重点重点,refreshToken保存下来,它只会在第一次请求中返回,后续用在发一样的请求不会返回refreshtoken,如果不慎弄丢了,需要去重新创建一个WebClientId ,这里切记哈

如果后续再次调用这个接口结果为:

 Step 8:使用refreshToken获取accessToken

地址:https://accounts.google.com/o/oauth2/token

请求方式:post

参数:grant_type=refresh_token

refresh_token=刚刚获取到的refreshToken

client_id=创建api项目是的clientId(客户端ID)

client_secret=创建api项目时的clientSecret(客户端密钥)

setp9:这一步也是最后一步了 就是查询订单状态:

查询订单状态

https://androidpublisher.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/products/{productId}/tokens/{token}?access_token={access_token}

packageName:app包名,必须是创建登录api项目时,创建android客户端Id使用包名

productId:对应购买商品的商品ID

token:购买成功后Purchase对象的getPurchaseToken()

access_token:上面咋们获取到的accessToken

请求方式:get

返回值解释:

{

"purchaseTimeMillis": "16239806",//购买产品的时间,自纪元(1970 年 1 月 1 日)以来的毫秒数。

"purchaseState": 0,//订单的购买状态。可能的值为:0. 已购买 1. 已取消 2. 待定

"consumptionState": 0,//产品的消费状态。可能的值为: 0. 尚未消耗 1. 已消耗

"developerPayload": "",

"orderId": "GPA.XXXXXXX8",//google订单号 "purchaseType": 0,

"acknowledgementState": 0,

"kind": "androidpublisher#productPurchase",

"obfuscatedExternalAccountId": "SDK2106180944530041",//上面客户支付时的透传字段,google指导是用来存放用户信息的,不能过长,否则客户端不能支付

"obfuscatedExternalProfileId": "",

"regionCode": "HK"

}

 其实服务端判断consumptionState就够了,如果是1 已经消费就可以实现后续逻辑了,比如发放金币,开启VIP等。

~~to: Ly

猜你喜欢

转载自blog.csdn.net/Jason_HD/article/details/130180064