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

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

1.前言在Java中的微信支付(1):APIV3版本签名详解一文中胖哥讲解了微信支付V3版本API的签名,当我方(你自己的服务器)请求微信支付服务器时需
d8aad2877413c88c8b0c62484e1bc4fc.gif

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 &#61; new ConcurrentHashMap<>();// 下面是刷新方法 refreshCertificate  的核心代码
String publicKey &#61; decryptResponseBody(associatedData, nonce, ciphertext);final CertificateFactory cf &#61; CertificateFactory.getInstance("X509");
ByteArrayInputStream inputStream &#61; new ByteArrayInputStream(publicKey.getBytes(StandardCharsets.UTF_8));
Certificate certificate &#61; null;try {
    certificate &#61; cf.generateCertificate(inputStream);
} catch (CertificateException e) {
    e.printStackTrace();
}
String responseSerialNo &#61; objectNode.get("serial_no").asText();// 清理HashMap
CERTIFICATE_MAP.clear();// 放入证书
CERTIFICATE_MAP.put(responseSerialNo, certificate);

动态刷新的策略就很好写了&#xff1a;

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

4. 总结

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

Java中的微信支付(1)&#xff1a;API V3版本签名详解

2020-10-24

465c29bb0f8254ac5247e997f602bbc4.png

XML和JSON互相转换原来这么简单

2020-10-22

a32f15c5e7e24a703604f148a6c51be3.png

f08b722ebae55df874a6b327adf6d2f1.png

535d197c28a00ab6240bef0d7ef95040.gif



推荐阅读
  • 采用IKE方式建立IPsec安全隧道
    一、【组网和实验环境】按如上的接口ip先作配置,再作ipsec的相关配置,配置文本见文章最后本文实验采用的交换机是H3C模拟器,下载地址如 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • Coursera ML 机器学习
    2019独角兽企业重金招聘Python工程师标准线性回归算法计算过程CostFunction梯度下降算法多变量回归![选择特征](https:static.oschina.n ... [详细]
  • 基于Node.js、Express、MongoDB和Socket.io的实时聊天应用开发
    本文详细介绍了使用Node.js、Express、MongoDB和Socket.io构建的实时聊天应用程序。涵盖项目结构、技术栈选择及关键依赖项的配置。 ... [详细]
  • 本文回顾了2017年的转型和2018年的收获,分享了几家知名互联网公司提供的工作机会及面试体验。 ... [详细]
  • 本教程详细介绍了如何使用 TensorFlow 2.0 构建和训练多层感知机(MLP)网络,涵盖回归和分类任务。通过具体示例和代码实现,帮助初学者快速掌握 TensorFlow 的核心概念和操作。 ... [详细]
  • 本文深入分析了 USDC 的稳定性和可能的救援措施,探讨了在硅谷银行破产后 USDC 面临的风险以及行业内的反应。 ... [详细]
  • 本文介绍如何从JSON格式的文件中提取数据并将其分配给Bash脚本中的变量。我们将探讨具体的命令和工具,帮助你高效地完成这一任务。 ... [详细]
  • Redux入门指南
    本文介绍Redux的基本概念和工作原理,帮助初学者理解如何使用Redux管理应用程序的状态。Redux是一个用于JavaScript应用的状态管理库,特别适用于React项目。 ... [详细]
  • 如何使用Ping命令来测试网络连接?当网卡安装和有关参数配置完成后,可以使用ping命令来测试一下网络是否连接成功。以winXP为例1、打开XP下DOS窗口具体操作是点击“开始”菜 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • Python 工具推荐 | PyHubWeekly 第二十一期:提升命令行体验的五大工具
    本期 PyHubWeekly 为大家精选了 GitHub 上五个优秀的 Python 工具,涵盖金融数据可视化、终端美化、国际化支持、图像增强和远程 Shell 环境配置。欢迎关注并参与项目。 ... [详细]
  • 版本控制工具——Git常用操作(下)
    本文由云+社区发表作者:工程师小熊摘要:上一集我们一起入门学习了git的基本概念和git常用的操作,包括提交和同步代码、使用分支、出现代码冲突的解决办法、紧急保存现场和恢复 ... [详细]
  • 本章详细介绍SP框架中的数据操作方法,包括数据查找、记录查询、新增、删除、更新、计数及字段增减等核心功能。通过具体示例和详细解析,帮助开发者更好地理解和使用这些方法。 ... [详细]
  • Android 6.0 切换指定 Wi-Fi 的解决方案
    本文详细介绍了在 Android 6.0 系统中切换到指定 Wi-Fi 的方法,包括常见的问题、原因分析及解决方案。通过官方文档和代码示例,帮助开发者更好地理解和实现这一功能。 ... [详细]
author-avatar
值兰修女_662
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有