1. 前言

Java中的微信支付(1):API V3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API证书对参数进行加签,微信服务器会根据我方签名验签以确定请求来自我方服务器。那么同样的道理我方的服务器也要对微信支付服务器的响应进行鉴别来确定响应真的来自微信支付服务器,这就是验签。验签使用的是【微信支付平台证书公钥】,不是商户API证书。使用商户API证书是验证不过的。今天就来分享一下如何获得微信平台公钥和动态刷新微信平台公钥。

2. 获取微信平台证书公钥

微信平台证书是微信支付平台自己的证书,我们是管不了的,而且是有效期的。

微信服务器会定期更换,所以也要求我方定期获取公钥。而且我们只能通过调用接口/v3/certificates来获得,此接口也需要进行签名(可参考上一篇文章)。你可以获取证书后静态放到服务器上,手动更新静态证书;也可以动态获取一劳永逸。本文采取一劳永逸的办法。

平台证书接口文档https://wechatpay-api.gitbook.io/wechatpay-api-v3/jie-kou-wen-dang/ping-tai-zheng-shu

3. 证书和回调报文解密

为了保证安全性,微信支付在回调通知平台证书下载接口中,对关键信息进行了AES-256-GCM加密。也就是说我们拿到响应的信息是被加密的,需要解密后才能获得真正的微信平台证书公钥。响应体大致是这样的,具体根据你调用平台证书接口,应该大差不差是下面这个结构:

{
"data": [
{
"effective_time": "2020-10-21T14:48:49+08:00",
"encrypt_certificate": {
// 加密算法
"algorithm": "AEAD_AES_256_GCM",
// 附加数据包(可能为空)
"associated_data": "certificate",
// Base64编码后的密文
"ciphertext": "",
// 加密使用的随机串初始化向量)
"nonce": "88b4e15a0db9"
},
"expire_time": "2025-10-20T14:48:49+08:00",
// 证书序列号
"serial_no": "217016F42805DD4D5442059D373F98BFC5252599"
}
]
}

你可以使用各种JSON类库取得下面方法的参数进行解密以获取证书,同时这里需要用到APIv3密钥,通用的解密方式为:

/**
* 解密响应体.
*
* @param apiV3Key API V3 KEY API v3密钥 商户平台设置的32位字符串
* @param associatedData response.body.data[i].encrypt_certificate.associated_data
* @param nonce response.body.data[i].encrypt_certificate.nonce
* @param ciphertext response.body.data[i].encrypt_certificate.ciphertext
* @return the string
* @throws GeneralSecurityException the general security exception
*/
public String decryptResponseBody(String apiV3Key,String associatedData, String nonce, String ciphertext) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8)); cipher.init(Cipher.DECRYPT_MODE, key, spec);
cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8)); byte[] bytes;
try {
bytes = cipher.doFinal(Base64Utils.decodeFromString(ciphertext));
} catch (GeneralSecurityException e) {
throw new IllegalArgumentException(e);
}
return new String(bytes, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
throw new IllegalStateException(e);
} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
throw new IllegalArgumentException(e);
}
}

回调的请求体也是此方法进行解密。

3. 动态刷新

然后就能拿到微信平台证书公钥。然后你可以定义个Map,以证书的序列号为KEY,以证书为Value来动态刷新,关键伪代码:

// 定义全局容器 保存微信平台证书公钥  注意线程安全
private static final Map<String, Certificate> CERTIFICATE_MAP = new ConcurrentHashMap<>(); // 下面是刷新方法 refreshCertificate 的核心代码
String publicKey = decryptResponseBody(associatedData, nonce, ciphertext); final CertificateFactory cf = CertificateFactory.getInstance("X509"); ByteArrayInputStream inputStream = new ByteArrayInputStream(publicKey.getBytes(StandardCharsets.UTF_8));
Certificate certificate = null;
try {
certificate = cf.generateCertificate(inputStream);
} catch (CertificateException e) {
e.printStackTrace();
}
String responseSerialNo = objectNode.get("serial_no").asText();
// 清理HashMap
CERTIFICATE_MAP.clear();
// 放入证书
CERTIFICATE_MAP.put(responseSerialNo, certificate);

动态刷新的策略就很好写了:

// 当证书容器为空 或者 响应提供的证书序列号不在容器中时  就应该刷新了
if (CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {
refreshCertificate();
}
// 然后调用
Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial);

4. 总结

虽然验签你不做可以拿到其它接口的响应结果,但是从资金安全的角度来说这是十分必要的。同时因为微信平台证书不收我方控制,采取动态刷新也会更加方便,不必再担心过期的问题。本文我们通过调用接口拿到密文并解密获得证书。下一篇我们将通过获得的证书进行签名验证来确保我们的响应是微信服务器发过来的,请关注:码农小胖哥 及时获得相关的更新。

关注公众号:Felordcn 获取更多资讯

个人博客:https://felord.cn

Java中的微信支付(2):API V3 微信平台证书的获取与刷新的更多相关文章

  1. 微信支付官方SDK V3 .NET版的坑

    但是支付成功后却不能正确的执行支付结果js回调函数.看看其页面的点击事件是放在asp:Button上面的.我们知道在asp.net webform中,按钮的点击是有页面回调后台的.也就是其实点击了之后 ...

  2. 微信支付之02------整个微信支付功能----------Java实现

    先来看下微信支付官方文档: 1.在官方文档上有很多种支付方式,由于目前我只做过JSAPI和微信扫码支付二种,其他的就不说了. >>>>>第一种微信扫码支付>> ...

  3. 微信支付——沙箱调试环境getsignkey方法秘钥获取及常见问题说明

    官方文档 :https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=23_1 微信支付PC二维码支付:https://www.cnblogs ...

  4. 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包

            微信支付教程系列之现金红包           最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...

  5. 【原创分享·微信支付】 C# MVC 微信支付教程系列之扫码支付

    微信支付教程系列之扫码支付                  今天,我们来一起探讨一下这个微信扫码支付.何为扫码支付呢?这里面,扫的码就是二维码了,就是我们经常扫一扫的那种二维码图片,例如,我们自己添 ...

  6. 【原创分享·微信支付】 C# MVC 微信支付教程系列之公众号支付

    微信支付教程系列之公众号支付         今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后再通 ...

  7. 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送

    微信支付之微信模板消息推送                    今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...

  8. 【分享·微信支付】 C# MVC 微信支付教程系列之公众号支付

    微信支付教程系列之公众号支付           今天,我们接着讲微信支付的系列教程,前面,我们讲了这个微信红包和扫码支付.现在,我们讲讲这个公众号支付.公众号支付的应用环境常见的用户通过公众号,然后 ...

  9. #PHP#微信支付 第二篇 JSAPI 调用统一下单接口获取预支付交易数据

    上一篇讲到成功获取 openid,本篇要调用微信统一接口创建预支付交易单,并获取到相关数据,以便(后边)在微信内调起H5支付 第三步,调用微信统一下单接口创建预支付交易单 微信统一下单API是微信支付 ...

随机推荐

  1. CCNP七层参考模型

    一.OSI七层参考模型 七层参考模型由ISO组织提出,为什么是参考模型呢?因为我们现在实际应用的是TCP/IP协议栈,OSI模型仅供学习参考,下面具体说一下有哪七层: (7)应用层:应用程序和服务功能 ...

  2. Redis小记(三)

    1.复制 通过slaveof命令或设置slaveof选项,实现一个服务器去复制另一个服务器,被复制的是主服务器,执行复制的是从服务器,复制过程中主从双方数据库保持数据一致 2.8版本以前,可分为初次复 ...

  3. 在KEIL下查看单片机编程内存使用情况

    原文链接:https://blog.csdn.net/D_azzle/article/details/83410141 截至到目前为止,本人接触单片机也有将近一年的时间.这一年以来也接触过了很具代表性 ...

  4. Raft 协议

    Paxos 存在的问题 Paxos 算法的描述偏学术化,缺失了很多细节,无法直接应用于工程领域.实际工程应用中的分布式算法大多是 Paxos 的变种,验证这些算法的正确性也成为了一个难题. 举个例子: ...

  5. 在sqlserver中创建表

    1:在sql语句中,临时表有两类,分别是局部(local)和全局(global)临时表,局部临时表只在其会话(事务)中可见,全局临时表可以被会话(事务)中的任何程序或者 模块访问 2:创建局部临时表 ...

  6. java高级项目 jdbc与数据库连接数据库

    //图书管类 public class Book { private Integer id; private String b_name; private double b_price; privat ...

  7. 推荐Java字节码解析工具classpy

    Classpy Classpy is a GUI tool for investigating Java class file, Lua binary chunk, Wasm binary code, ...

  8. 连Python产生器(Generator)的原理都解释不了,还敢说Python用了5年?

      最近有很多学Python同学问我,Python Generator到底是什么东西,如何理解和使用.Ok,现在就用这篇文章对Python Generator做一个敲骨沥髓的深入解析.   为了更好地 ...

  9. ABP vnext模块化架构的最佳实践的实现

    在上一篇文章<手把手教你用Abp vnext构建API接口服务>中,我们用ABP vnext实现了WebAPI接口服务,但是并非ABP模块化架构的最佳实践.我本身也在学习ABP,我认为AB ...

  10. 2014年 实验四 B2B模拟实验(二)

    [实验目的] ⑴.熟悉电子合同签订过程 ⑵.掌握网上招标的流程并体会招标对采购商带来的好处 [实验条件] ⑴.个人计算机一台 ⑵.计算机通过局域网形式接入互联网 ⑶.电子商务模拟实验室软件包. [知识 ...