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 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();// 清理HashMapCERTIFICATE_MAP.clear();// 放入证书CERTIFICATE_MAP.put(responseSerialNo, certificate);

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

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

4. 总结

虽然验签你不做可以拿到其它接口的响应结果,但是从资金安全的角度来说这是十分必要的。同时因为微信平台证书不收我方控制,采取动态刷新也会更加方便,不必再担心过期的问题。本文我们通过调用接口拿到密文并解密获得证书。

往期资源  需要请自取

真香警告!Alibaba珍藏版mybatis手写文档,刷起来

卧槽!字节跳动《算法中文手册》火了,完整版 PDF 开放下载

字节跳动总结的设计模式 PDF 火了,完整版开放下载!

别辛苦找学习视频拉,请收下程序汪整理的50个Java项目实战视频

10k+点赞的Spring Boot后台管理系统竟然出了详细教程!

aes加密 java_Java中的微信支付(2):API V3 微信平台证书的获取与刷新相关推荐

  1. Java中的微信支付(2):API V3 微信平台证书的获取与刷新

    1. 前言 在Java 中的微信支付(1):API V3 版本签名详解一文中胖哥讲解了微信支付 V3 版本 API 的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API 证书对参数 ...

  2. ansible 建 kubernetes 证书签名请求_Java中的微信支付(2):API V3 微信平台证书的获取与刷新...

    1. 前言 在Java 中的微信支付(1):API V3 版本签名详解一文中胖哥讲解了微信支付 V3 版本 API 的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API 证书对参数 ...

  3. java读取微信证书_Java中的微信支付(2):API V3 微信平台证书的获取与刷新

    1. 前言 在Java中的微信支付(1):API V3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API证书对参数进行加签,微信 ...

  4. java 微信https 证书_Java中的微信支付(2):API V3 微信平台证书的获取与刷新

    1. 前言 在Java中的微信支付(1):API V3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需要根据我方的API证书对参数进行加签,微信 ...

  5. Java中的微信支付:API V3对微信服务器响应进行签名验证3

    前言 牢记一句话:公钥加密,私钥解密:私钥加签,公钥验签. 微信支付V3版本前两篇分别讲了如何对请求做签名和如何获取并刷新微信平台公钥,本篇将继续展开如何对微信支付响应结果的验签. 2. 为什么要对响 ...

  6. 微信实现APP下单接口(微信支付开发API V3接口调用)

    准备工作 : 有微信商户平台 : mchid:微信商户id appid:商户appid 商户证书:商户可登录微信商户平台,在[账户中心]->[API安全]目录下载证书 证书文件名 :apicli ...

  7. 微信支付项目四:微信支付笔记

    1. 微信支付项目四:微信支付交付 文章目录 1. 微信支付项目四:微信支付交付 1.1. 微信支付交付方式 1.2. 互联网架构知识时序图 1.3. 微信支付模式二的时序图 1.4. 微信支付订单接 ...

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

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

  9. 微信支付接口怎么申请 微信支付接口申请教程

     微信支付接口:点击进去 一直让大家翘首以盼的微信最核心的杀手锏--"微信支付"终于开放申请了!今天微信团队在官网发布消息,微信公众平台支付功能已正式开放申请,已开通公众号的 ...

最新文章

  1. xamarin ios html5 video.js 无法播放
  2. Nodejs连接mysql的增、删、改、查操作
  3. python基本程序结构有几种_python基础梳理(一)(推荐)
  4. 利用滞后——超前系统解决高阶随动系统(课程设计)
  5. Linux装ntfs后内存不够,Linux_安装Ubuntu后无法使用NTFS硬盘或移动硬盘,  在安装Ubuntu系统后,存在 - phpStudy...
  6. oracle read by other session,AWR报告中,read by other session ,如何解决?
  7. BGP中的联盟原理和实验(华为设备)
  8. 算法:判断树是否相同100. Same Tree
  9. 【代码优化】坚持使用Override注解
  10. 白帽飞客从入门到放肆
  11. 音箱后面接口 COM 8欧 70V 100V
  12. 为什么 React17-rc.2 要发布新的 jsx 转换逻辑
  13. win7 开wifi 关wifi
  14. 阿里云mysql空间不足_阿里云数据库MySQL系统文件导致实例空间满的解决办法
  15. 基于大数据的情报分析与服务系统架构设计
  16. 李政道和杨振宁合作历程
  17. Python实时检测文件及文件夹变动
  18. LINUX信息安全系统设计基础第一周学习总结
  19. Learning Representations for(三)
  20. 【树莓派不吃灰】命令篇⑥ 了解树莓派Boot分区,学习Linux启动流程

热门文章

  1. android之ShareSDK实现分享功能
  2. 便签里的文件怎么传输给别人
  3. 对话框AlertDialog的基本使用(新手)
  4. 移动互联网的5大思维和10个法则
  5. 科达高空瞭望系列摄像机案例分享
  6. 生活明朗,万物可爱,人间值得,未来可期
  7. html, css学习笔记,自用(B站黑马程序员pink老师)
  8. dotNetFx40_Client_x86_x64和dotNetFx40_Full_x86_x64这两个有什么区别?两个都要安装还是安装其中一个?...
  9. 已解决:好用的集成PHP环境 一键安装包PHPNow--Win7下安装phpnow的方法出现[ Apache_pn ] 错误的解决 !(亲自测试通过)
  10. 字典dict.pop()和del dict[]的区别与联系