第三方应用开发者如何正确代商家调用支付宝支付接口实现安全收款
在第三方应用中,开发者的身份通常是服务商,需代商家调用接口来完成收款业务。之前我认为支付业务仅仅需要传递交易金额、订单号、交易双方的支付宝账号以及在支付宝开放平台申请到的 appId、应用私钥、支付宝公钥,然后调用接口即可。但仔细阅读过官方 API 文档后,我发现订单交易并非通过传入交易双方的支付宝账号来进行。传入交易双方的支付宝账号一般适用于支付宝的双方转账场景,比如提现、分佣等。商家自行研发的应用需要传入 appId 来实现收款。在数据传输过程中,应用的私钥和支付宝的公钥会对接口信息进行加解密,这样可以防止接口信息被人截获和篡改。第三方应用中存在一个重要问题。与商家自研应用相比,服务商需代商家调用支付接口。不能通过传入支付宝账号来满足每个商家的支付需求,无法将款打到商家对应的账户上。而支付宝开放平台给出了相关文档说明。

小程序文档在支付宝文档中心可以通过用户授权来获取用户信息,同时也能够拿到 openId。
图一 第三方应用邀请商家授权
图二 获取app_auth_token业务流程图
找到上面的文档进行研究后,我的思路变得清晰了许多。我们进入第三方应用后台,然后按照流程完整地进行一次操作。
我们进入到第三方应用的后台,接着依次点击“商家授权”,然后点击邀请商家授权按钮。
点击后,我们进入到“邀请商家授权”的页面。在这个页面上,可以看到有通过二维码和链接这两种方式。我们能够把二维码和 PC 端链接渲染到我们的应用当中,以便让商家通过扫码来进行授权。这里,我们以在浏览器中输入 PC 端链接作为示例。
打开 PC 端链接后,我们需要选择要授权的应用,接着勾选服务条款,然后点击“确认处理代办”按钮。
商家授权成功后会自动开启授权回调地址,同时 app_auth_code 会被拼接到路由中。第三方应用后台开发设置中需配置授权回调地址,商家授权后会自动跳转至该回调地址,并以路由传参的方式传递参数。所以该授权回调地址必须存在且部署到服务器上。
邀请商家授权后,我们能够看到 app_auth_code 已传到回调地址中。接着,我们需要编写好程序,在页面中获取这些路径参数。当页面打开时,把这些参数传到后端,以换取 app_auth_token。
下面附上我的页面源代码:
商家授权成功
后端拿到 app_auth_code 之后,需要依据官方文档来换取 app_auth_token。在拿到 app_auth_token 之后,我们还得把 app_auth_token 存储到数据库中,这样便于调用支付接口。下面附上我的后端源代码:
6.1.Maven依赖:
com.alipay.sdk
alipay-sdk-java
4.39.113.ALL
6.2.控制层代码
/**
*
* @param authCode
@param sellerId 它对应着我数据库中表的主键 ID,这样做的目的是能够方便地将 app_auth_token 更新到商家表当中。
* @return
* @throws AlipayApiException
*/
@GetMapping("/updateToken")
公共结果类的 updateToken 方法,接收一个字符串类型的 authCode 和一个长整型的 sellerId 作为参数,并且会抛出 AlipayApiException 异常。
卖家服务更新令牌(认证码,卖家 ID)。
return Result.success();
}
6.3.业务层代码
公共的 void 方法用于更新令牌,该方法接收一个字符串类型的授权码和一个长整型的卖家 ID 作为参数,并且会抛出支付宝 API 异常。
AliPayConfig 被创建了一个实例,这个实例就是 aliPayConfig。
AlipayClient 被创建出来,创建的对象名为 alipayClient ,它是通过 new 操作符来实现创建的。
创建 DefaultAlipayClient 对象,其参数包括请求地址为 "https://openapi.alipay.com/gateway.do",应用 ID 为 aliPayConfig.getAppId(),私钥为 aliPayConfig.getPrivateKey(),数据格式为 "json",字符编码为 "GBK",支付宝公钥为 aliPayConfig.getPublicKey(),加密算法为 "RSA2"
// 构造请求参数以调用接口
AlipayOpenAuthTokenAppRequest 被创建了一个实例,这个实例被命名为 request 。
创建了一个名为 AlipayOpenAuthTokenAppModel 的模型,这个模型被赋值给了变量 model 。
// 设置授权方式
模型设置授权类型为“authorization_code”。
// 设置应用授权码
model.setCode(authCode);
// 设置刷新令牌
模型把 "201509BBdcba1e3347de4e75ba3fed2c9abebE36" 作为自身的刷新令牌进行设置。
request.setBizModel(model);
// 第三方代调用模式下请设置app_auth_token
请求设置其他文本参数,参数名为"app_auth_token",参数值为"<-- 请填写应用授权令牌 -->");
AlipayClient 执行了请求,生成了 AlipayOpenAuthTokenAppResponse 响应。
打印 response 的主体内容。
if (response.isSuccess()) {
System.out.println("调用成功");
sellerMapper 使用 response 中的 AppAuthToken 和 AuthAppId 以及 sellerId 来更新 Token
} else {
System.out.println("调用失败");
sdk 版本为“4.38.0.ALL”或者比它更高时,能够参考以下示例来获取诊断链接。
获取诊断相关的 URL 可以通过 DiagnosisUtils.getDiagnosisUrl(response)来实现。
System.out 会打印出 diagnosisUrl 。
}
}
6.4.dao层代码
定义一个名为 updateToken 的方法,该方法接收三个参数,分别是 appAuthToken、authAppId 和 sellerId,其中 appAuthToken 为字符串类型,通过 @Param("appAuthToken") 注解标识,authAppId 为字符串类型,通过 @Param("authAppId") 注解标识,sellerId 为长整型,通过 @Param("sellerId") 注解标识。
更新卖家信息,将其授权令牌设置为#{appAuthToken},将其应用 ID 设置为#{authAppId}
where id = #{sellerId}
通过上面的演示,我们已经获取到了 app_auth_token 并且将其存到了数据库中。现在我们来思考一个问题,为什么能够把 app_auth_token 存到数据库里呢?难道这么重要的参数不会一直更新吗?
app_auth_token有效期说明
官方对 app_auth_token 有解释,从这个解释可以看出,把 app_auth_token 插入数据库是有必要的,并且也是可行的。
服务商向商家提供新业务时,需商家授予新权限。商家需再次扫码对应用重新授权,在此情况下,原来的 app_auth_token 会失效,同时会生成一个新的 app_auth_token。但是每次我们都能够凭借商家登录账号获取到商家 ID。商家重新进行授权之后,就可以即刻对数据库进行更新。这只是将上述的流程又重新走了一遍而已。
有了上述的铺垫之后,在代商家调用接口时,能够通过设置入参 app_auth_token 来达成业务需求。
request 将其他文本参数设置为 "app_auth_token",并将其值设置为 authToken。
我来简单介绍一下自己。我是一名本科生。在暑期实习期间,由于公司有支付业务的需求,我以服务商的身份学习了支付宝开放平台的相关文档。在实践过程中,我遇到了很多困惑,也真正有了很多体会。我发布这篇文章,希望能够真正帮助到大家。同时,如果文章中有不严谨的地方,也欢迎各位指正。
星光不会辜负赶路的人。梦想无论多么遥远,只要持之以恒,就必定能够达成自己的理想。加油!