1. 前言

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

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

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

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

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();

// 清理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. 总结

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

关注公众号:码农小胖哥,获取更多资讯

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

  1. java读取文件 路径_Java中的获取文件的物理绝对路径,和读取文件

    获取文件的绝对路径,读取该文件 一.文件目录打印图 下面的文件目录图,是项目中文件的位置信息:下面的例子是按照这个图来演示的. . |-- java | |-- ibard | | |-- demo1 ...

  2. java 读取文件 二进制_JAVA中读取文件(二进制,字符)内容的几种方法总结

    public class ReadFromFile { /** * 以字节为单位读取文件,常用于读二进制文件,如图片.声音.影像等文件. */ public static void readFileB ...

  3. java file类包_Java中File类的常用API

    Java.io包下的File类实现了Serializable和Comparable两个接口 1.创建文件 注意: 1).如果D盘下file文件夹不存在,则抛出异常;如果D盘下file文件夹存在,则创建 ...

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

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

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

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

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

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

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

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

  8. java 读取集合到流中_Java 10:将流收集到不可修改的集合中

    java 读取集合到流中 Java 10引入了几种新方法来促进不可修改集合的创建. List.copyOf , Set.copyOf和Map.copyOf方法从现有实例创建新的集合实例. 例如: Li ...

  9. 微信公众号中的支付宝支付与微信支付 支付宝支付问题(微信bug)

    一般,在微信公众号中的商城都是需要支持微信支付和支付宝支付的,当然,较大的公司对于鹅厂和阿里的站队就不说了,所以这里简单记录一下支付宝支付和微信支付的主要流程.说是简单介绍,这是因为确实不难,因为前端 ...

最新文章

  1. 笔记-项目风险管理-复习要点
  2. spark 算子使用类变量_自己工作中超全spark性能优化总结
  3. 在html中设置常量并做判断,写一篇我所理解的javascript编程规范
  4. 雷军立 Flag:小米 5 年 100 亿 All in AIoT
  5. 微软2月修复99个漏洞,含1个 0day
  6. 线性支持向量机与软间隔最大化
  7. Oracle 数据库常用操作总结一之用户的创建、删除和赋权
  8. Tunatic(歌曲识别软件)v1.0.1官方版
  9. CentOS 识别NTFS格式U盘
  10. 标准更新|这次是OTA的EN301908-13即增加TRP和TRS的测试要求
  11. 第十三届蓝桥杯模拟赛第二期JAVA组个人题解
  12. 计算机应用基础网上作业2,华东理工 计算机应用基础(本)网上作业2
  13. 刚生了宝宝后需要及时办理的6个证件
  14. 【安卓笔记】自定义toggleButton
  15. shell bash
  16. git常见的命令大全
  17. 机器阅读理解技术初探Bi-DAF
  18. 烤仔观察 | wēi?wéi!wěi?wèi?
  19. 大数据如何在前端流畅展示
  20. 在WORD中自动生成目录,页码

热门文章

  1. 分布式服务架构下的身份认证
  2. Python WebDriver API - 浏览器窗口操作
  3. 熊猫烧香病毒技术分析及应急解决方案
  4. java实况足球2014,有趣的足球题材游戏有哪些
  5. iphone免越狱插件_如何保护iPhone免受盗贼的侵害
  6. 如何使用CSS和JavaScript构建简单的甘特图
  7. 理解字节填充和零比特填充
  8. 【.Net码农】【淘宝API】淘宝API应用开发小试
  9. linux split到指定目录,split命令_Linux split命令:切割(拆分)文件
  10. 您的企业已经准备好使用专线了吗?——Vecloud