Java中的微信支付(2):API V3 微信平台证书的获取与刷新
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. 总结
虽然验签你不做可以拿到其它接口的响应结果,但是从资金安全的角度来说这是十分必要的。同时因为微信平台证书不收我方控制,采取动态刷新也会更加方便,不必再担心过期的问题。本文我们通过调用接口拿到密文并解密获得证书。下一篇我们将通过获得的证书进行签名验证来确保我们的响应是微信服务器发过来的,请关注下方公众号:码农小胖哥 及时获得相关的更新。
往期推荐
MIT黑科技:通过手机记录的咳嗽数据检测是否感染新冠病毒
为什么我使用了索引,查询还是慢?
10个你可能不曾用过却很有用的 LINUX 命令
分享一个Java开发都用得到的密码摘要算法包
程序员编码时都戴耳机?到底在听什么?
Spring Data 发布更改版本管理方案之后的第一个版本:2020.0.0
﹀
﹀
﹀
深度内容
推荐加入
最近热门内容回顾 #技术人系列
Java中的微信支付(2):API V3 微信平台证书的获取与刷新相关推荐
- java读取微信证书_Java中的微信支付(2):API V3 微信平台证书的获取与刷新
1. 前言 在Java中的微信支付(1):API V3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API证书对参数进行加签,微信 ...
- java 微信https 证书_Java中的微信支付(2):API V3 微信平台证书的获取与刷新
1. 前言 在Java中的微信支付(1):API V3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API证书对参数进行加签,微信 ...
- ansible 建 kubernetes 证书签名请求_Java中的微信支付(2):API V3 微信平台证书的获取与刷新...
1. 前言 在Java 中的微信支付(1):API V3 版本签名详解一文中胖哥讲解了微信支付 V3 版本 API 的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API 证书对参数 ...
- aes加密 java_Java中的微信支付(2):API V3 微信平台证书的获取与刷新
1. 前言 在Java 中的微信支付(1):API V3 版本签名详解一文中胖哥讲解了微信支付 V3 版本 API 的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API 证书对参数 ...
- Java中的微信支付:API V3对微信服务器响应进行签名验证3
前言 牢记一句话:公钥加密,私钥解密:私钥加签,公钥验签. 微信支付V3版本前两篇分别讲了如何对请求做签名和如何获取并刷新微信平台公钥,本篇将继续展开如何对微信支付响应结果的验签. 2. 为什么要对响 ...
- 微信实现APP下单接口(微信支付开发API V3接口调用)
准备工作 : 有微信商户平台 : mchid:微信商户id appid:商户appid 商户证书:商户可登录微信商户平台,在[账户中心]->[API安全]目录下载证书 证书文件名 :apicli ...
- ASP.NET Google Maps Javascript API V3 实战基础篇一获取和设置事件处理程序中的属性...
ASP.NET Google Maps Javascript API V3 实战基础篇一获取和设置事件处理程序中的属性 <%@ Page Language="C#" Auto ...
- 微信支付官方SDK V3 .NET版的坑
但是支付成功后却不能正确的执行支付结果js回调函数.看看其页面的点击事件是放在asp:Button上面的.我们知道在asp.net webform中,按钮的点击是有页面回调后台的.也就是其实点击了之后 ...
- android 微信支付下单,android端微信支付V3版本地签名统一下单详解
满满的都是坑,因为服务器偷懒让客服端写统一下单,服务器只给了通知的url.微信的支付demo并没有统一下单的代码. 读此文前先阅读: https://pay.weixin.qq.com/wiki/do ...
最新文章
- spring实例教程
- 为进大厂刷爆算法题,最后却倒在了基础题上?太苦了!
- python笔记之while和for循环练习
- Python Threading 多线程编程
- 在收购 Sun 的六年后,Oracle 终于瞄准了 Java 的非付费用户
- Apache Camel –从头开始开发应用程序(第2部分/第2部分)
- 我的mongoose代码备份
- 好程序员前端分享使用JS开发简单的音乐播放器
- Struts2源码阅读(一)_Struts2框架流程概述
- 56 FI配置-财务会计-固定资产-资产数据传输-定义历史数据传输的抵销科目
- linux磁盘满了之后清理
- mysql存储过程 大小写_MySQL数据记录大小写敏感问题【转】
- 安装phpmyadmin
- java浮点数的精确计算_Java 浮点数计算精度丢失问题?
- html 倒计时弹出框,javascript实现倒计时提示框
- 如何彻底卸载AutoCAD 2018版
- 关于电的计算机公式,关于电的计算公式 所有注意,是所有!什么功率、电流、电阻、.对不起,我要的是全部,而且不要光是字母公式,而且请注明单位...
- 如何查看计算机网络日志,电脑系统日志怎么查看 电脑怎么查看使用记录
- 最全Linux面试题
- SpringBoot - @SpringBootTest加速单元测试的小窍门