热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

APIv3版微信支付平台证书获取与自动更新

APIv3版微信支付平台证书获取与自动更新关于微信证书获取平台证书证书自动更新首次下载证书关于微信证书微信支付开发有两份证书。商户证书:商户平台证书私钥可以对请求进行签名,微信服务

API v3版微信支付平台证书获取与自动更新

    • 关于微信证书
    • 获取平台证书
    • 证书自动更新
    • 首次下载证书

关于微信证书

微信支付开发有两份证书。
商户证书:商户平台证书私钥可以对请求进行签名,微信服务器进行验签可以验证请求者的身份和合法性;
微信平台证书:是由微信服务器使用私钥对响应签名之后,我们自己的服务器使用平台证书对响应进行验签,从而可以验证响应的合法性。

获取平台证书

微信官网有对应的API可以获取平台证书,请求之前也需要进行相应的签名,响应的数据大致如下。
若有新旧证书更替,则可能不止一条证书数据存在,且ciphertext证书字段为密文传输,需要对其进行解密才能正常使用。
解密使用的对称密钥是在微信平台(微信平台传送门)进行设置。【商户平台】->【API安全】->设置API v3密钥(注意不是API密钥)

{
"data": [
{
"serial_no": "5157F09EFDC096DE15EBE81A47057A7232F1B8E1",
"effective_time ": "2018-06-08T10:34:56+08:00",
"expire_time ": "2018-12-08T10:34:56+08:00",
"encrypt_certificate": {
"algorithm": "AEAD_AES_256_GCM",
"nonce": "61f9c719728a",
"associated_data": "certificate",
"ciphertext": "sRvt… "
}
},
{
"serial_no": "50062CE505775F070CAB06E697F1BBD1AD4F4D87",
"effective_time ": "2018-12-07T10:34:56+08:00",
"expire_time ": "2020-12-07T10:34:56+08:00",
"encrypt_certificate": {
"algorithm": "AEAD_AES_256_GCM",
"nonce": "35f9c719727b",
"associated_data": "certificate",
"ciphertext": "aBvt… "
}
}
]
}

解密响应体,解密ciphertext证书字段代码。

/** * 使用微信平台证书对响应验签,和应答签名比较 * @param wechatpaySerial response.headers['Wechatpay-Serial'] 当前使用的微信平台证书序列号 * @param wechatpaySignature response.headers['Wechatpay-Signature'] 微信平台签名 * @param wechatpayTimestamp response.headers['Wechatpay-Timestamp'] 微信服务器时间戳 * @param wechatpayNonce response.headers['Wechatpay-Nonce'] 微信服务器提供的随机串 * @param body response.headers['Wechatpay-body'] 微信服务器的响应体 * @return boolean * @throws SignatureException */
public boolean responseSignVerify(String wechatpaySerial, String wechatpaySignature, String wechatpayTimestamp, String wechatpayNonce, String body) {
log.info("WXPayUtil responseSignVerify start : wechatpaySerial = " + wechatpaySerial +
", wechatpaySignature = " + wechatpaySignature + ", wechatpayTimestamp = " + wechatpayTimestamp +
", wechatpayNOnce= " + wechatpayNonce + ", body = " + body);

if(CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
refreshCertificate();
}

Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial);
// log.info("WXPayUtil responseSignVerify CERTIFICATE_MAP证书:certificate" + certificate);

// 构造验签名串
final String strSignature = responseSign(wechatpayTimestamp, wechatpayNonce, body);

log.info("WXPayUtil responseSignVerify 构造验签名串 strSignature : " + strSignature);

try {
// 加载 SHA256withRSA 签名器
Signature signer = Signature.getInstance(SIGN_INSTANCE_SHA256WITHTSA);
// 用微信平台公钥对签名器进行初始化
signer.initVerify(certificate);
// 将验签名串更新到签名器中
signer.update(strSignature.getBytes(StandardCharsets.UTF_8));

boolean ret = signer.verify(Base64Utils.decodeFromString(wechatpaySignature));
log.info("WXPayUtil responseSignVerify 验签结果 ret = " + ret);

return ret;
} catch (NoSuchAlgorithmException | SignatureException e) {
// TODO Auto-generated catch block
throw new IllegalStateException(e);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
throw new IllegalArgumentException(e);
}
}

证书自动更新

微信平台为了保证安全,定期会更换平台证书,这时我们自己的系统就需要自动更新对应证书来验签。


private static final Map<String, Certificate> CERTIFICATE_MAP = new ConcurrentHashMap<String, Certificate>();
/** * 证书动态刷新,将最新的证书放入Map中 * */
public void refreshCertificate(){

WXPayNativeService nativeService = new WXPayNativeService();

java.util.List<WXPlatCertificate> respCertList = nativeService.getWXCertList();

log.info("NativeService-refreshCertificate 请求返回数据为:" + respCertList);

// 选用证书启用时间最晚的证书
List<WXPlatCertificate> wx = respCertList.stream()
.sorted(Comparator.comparing((WXPlatCertificate w) -> w.getEffective_time()))
.collect(Collectors.toList());
WXPlatCertificate wxPlatCertificate = wx.get(0);
WXPlatCertificate wxPlatCertificate = respCertList.get(0);
log.info("NativeService-refreshCertificate wxPlatCertificate 最近的证书为:" + wxPlatCertificate);
// respCertList.stream().sorted()
// 解密返回数据,得到证书
String publicKey = WXPayUtil.decryptResponseBody(WXPayUtil.getConfigProperties("WX_APIV3_SYMMETRIC_KEY"),
wxPlatCertificate.getEncrypt_certificate().getAssociated_data(),
wxPlatCertificate.getEncrypt_certificate().getNonce(),
wxPlatCertificate.getEncrypt_certificate().getCiphertext());
log.info("NativeService-getConfigProperties 解密返回数据,publicKey1:" + publicKey);
try {
final CertificateFactory cf = CertificateFactory.getInstance("X509");

ByteArrayInputStream inputStream = new ByteArrayInputStream(publicKey.getBytes(StandardCharsets.UTF_8));

Certificate certificate = cf.generateCertificate(inputStream);

String responseSerialNo = wxPlatCertificate.getSerial_no();

System.out.println("NativeService-getConfigProperties 证书序列号为serial_no:" + responseSerialNo);
// 清空HashMap()
CERTIFICATE_MAP.clear();
// 放入证书
CERTIFICATE_MAP.put(responseSerialNo, certificate);

} catch (CertificateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

首次下载证书

首次下载证书的时候,这时候我们本地是没有证书的,所以下载证书的请求不能进行验签,否则可能会出现循环调用的情况,微信平台提供了工具可以进行第一次的证书下载。(微信证书下载工具)
将jar包下载之后cmd输入命令即可下载。当然也可以选择不进行验签。
《API v3版微信支付平台证书获取与自动更新》

java -jar F:\WXpayDemo\CertificateDownloader-1.1.jar
-k erexxxrxxxxxxxxxxxxxxxxjled
-m 15xxxxxxxxx61
-f F:\WXpayDemo\param\apiclient_key.pem
-s 23B3AxxxxxxxxxxxxxxxxxxxxxxxC90B50
-o F:\WXpayDemo

完整命令如下:

java -jar F:\WXpayDemo\CertificateDownloader.jar -k java -jar F:\WXpayDemo\CertificateDownloader-1.1.jar -k erexxxrxxxxxxxxxxxxxxxxjled -m 15xxxxxxxxx61 -f F:\WXpayDemo\param\apiclient_key.pem -s 23B3AxxxxxxxxxxxxxxxxxxxxxxxC90B50 -o F:\WXpayDemo

证书下载完成之后就可以对响应进行验签。

相关文章链接:

API v3版微信支付开发JAVA
API v3版微信支付请求签名
API v3版微信支付 验签


推荐阅读
  • 2018-2019学年第六周《Java数据结构与算法》学习总结
    本文总结了2018-2019学年第六周在《Java数据结构与算法》课程中的学习内容,重点介绍了非线性数据结构——树的相关知识及其应用。 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
  • 我有一个SpringRestController,它处理API调用的版本1。继承在SpringRestControllerpackagerest.v1;RestCon ... [详细]
  • 深入理解Vue.js:从入门到精通
    本文详细介绍了Vue.js的基础知识、安装方法、核心概念及实战案例,帮助开发者全面掌握这一流行的前端框架。 ... [详细]
  • Redux入门指南
    本文介绍Redux的基本概念和工作原理,帮助初学者理解如何使用Redux管理应用程序的状态。Redux是一个用于JavaScript应用的状态管理库,特别适用于React项目。 ... [详细]
  • 本文总结了优化代码可读性的核心原则与技巧,通过合理的变量命名、函数和对象的结构化组织,以及遵循一致性等方法,帮助开发者编写更易读、维护性更高的代码。 ... [详细]
  • ElasticSearch 集群监控与优化
    本文详细介绍了如何有效地监控 ElasticSearch 集群,涵盖了关键性能指标、集群健康状况、统计信息以及内存和垃圾回收的监控方法。 ... [详细]
  • 本教程详细介绍了如何使用 TensorFlow 2.0 构建和训练多层感知机(MLP)网络,涵盖回归和分类任务。通过具体示例和代码实现,帮助初学者快速掌握 TensorFlow 的核心概念和操作。 ... [详细]
  • 本文介绍如何使用 Angular 6 的 HttpClient 模块来获取 HTTP 响应头,包括代码示例和常见问题的解决方案。 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 云函数与数据库API实现增删查改的对比
    本文将深入探讨使用云函数和数据库API实现数据操作(增删查改)的不同方法,通过详细的代码示例帮助读者更好地理解和掌握这些技术。文章不仅提供代码实现,还解释了每种方法的特点和适用场景。 ... [详细]
  • 本文将详细介绍多个流行的 Android 视频处理开源框架,包括 ijkplayer、FFmpeg、Vitamio、ExoPlayer 等。每个框架都有其独特的优势和应用场景,帮助开发者更高效地进行视频处理和播放。 ... [详细]
  • 使用PHP实现网站访客计数器的完整指南
    本文详细介绍了如何利用PHP构建一个简易的网站访客统计系统。通过具体的代码示例和详细的解释,帮助开发者理解和实现这一功能,适用于初学者和有一定经验的开发人员。 ... [详细]
  • 黑马头条项目:Vue 文章详情模块与交互功能实现
    本文详细介绍了如何在黑马头条项目中配置文章详情模块的路由、获取和展示文章详情数据,以及实现关注、点赞、不喜欢和评论功能。通过这些步骤,您可以全面了解如何开发一个完整的前端文章详情页面。 ... [详细]
  • 版本控制工具——Git常用操作(下)
    本文由云+社区发表作者:工程师小熊摘要:上一集我们一起入门学习了git的基本概念和git常用的操作,包括提交和同步代码、使用分支、出现代码冲突的解决办法、紧急保存现场和恢复 ... [详细]
author-avatar
xkxk22
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有