1. 前言

牢记一句话:公钥加密,私钥解密;私钥加签,公钥验签。

微信支付V3版本前两篇分别讲了如何对请求做签名和如何获取并刷新微信平台公钥,本篇将继续展开如何对微信支付响应结果的验签。

2. 为什么要对响应验签

微信支付会在回调的HTTP头部中包括回调报文的签名。商户必须验证响应的签名,保证响应确实来自微信支付服务器,避免中间人攻击。而验证响应签名除了需要微信平台的公钥外还需要从请求头的其它参数。

假设以下就是微信支付服务器的响应:

HTTP/1.1 200 OK

Server: nginx

Date: Tue, 02 Apr 2019 12:59:40 GMT

Content-Type: application/json; charset=utf-8

Content-Length: 2204

Connection: keep-alive

Keep-Alive: timeout=8

Content-Language: zh-CN

Request-ID: e2762b10-b6b9-5108-a42c-16fe2422fc8a

Wechatpay-Nonce: c5ac7061fccab6bf3e254dcf98995b8c

Wechatpay-Signature: CtcbzwtQjN8rnOXItEBJ5aQFSnIXESeV28Pr2YEmf9wsDQ8Nx25ytW6FXBCAFdrr0mgqngX3AD9gNzjnNHzSGTPBSsaEkIfhPF4b8YRRTpny88tNLyprXA0GU5ID3DkZHpjFkX1hAp/D0fva2GKjGRLtvYbtUk/OLYqFuzbjt3yOBzJSKQqJsvbXILffgAmX4pKql+Ln+6UPvSCeKwznvtPaEx+9nMBmKu7Wpbqm/+2ksc0XwjD+xlvlECkCxfD/OJ4gN3IurE0fpjxIkvHDiinQmk51BI7zQD8k1znU7r/spPqB+vZjc5ep6DC5wZUpFu5vJ8MoNKjCu8wnzyCFdA==

Wechatpay-Timestamp: 1554209980

Wechatpay-Serial: 5157F09EFDC096DE15EBE81A47057A7232F1B8E1

Cache-Control: no-cache, must-revalidate

{"prepay_id":"wx2922034726858082fbd40b511c67630000"}

检查平台证书序列号

微信支付响应的时候会携带一个微信平台证书序列号,从响应头中的Wechatpay-Serial字段中获取值,用来提示我们要使用该序列号的证书来进行验签,如果不存在就需要我们刷新证书,而上一文我们将平台证书序列号和证书以键值对存在HashMap中,我们只需要检查是否存在即可,不存在就刷新。

构造验签名串

从响应结果中获取对应下面方法的三个参数就可以构造出验签名串。

/**

* 构造验签名串.

*

* @param wechatpayTimestamp HTTP头 Wechatpay-Timestamp 中的应答时间戳。

* @param wechatpayNonce HTTP头 Wechatpay-Nonce 中的应答随机串

* @param body 响应体

* @return the string

*/

public String responseSign(String wechatpayTimestamp, String wechatpayNonce, String body) {

return Stream.of(wechatpayTimestamp, wechatpayNonce, body)

.collect(Collectors.joining("\n", "", "\n"));

}

验证签名

待验证的签名从响应头中的Wechatpay-Signature字段中获取,我们使用微信支付平台公钥对验签名串和签名进行SHA256 with RSA签名验证。

// 构造验签名串

final String signatureStr = responseSign(wechatpayTimestamp, wechatpayNonce, body);

// 加载SHA256withRSA签名器

Signature signer = Signature.getInstance("SHA256withRSA");

// 用微信平台公钥对签名器进行初始化

signer.initVerify(certificate);

// 把我们构造的验签名串更新到签名器中

signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));

// 把请求头中微信服务器返回的签名用Base64解码 并使用签名器进行验证

boolean result = signer.verify(Base64Utils.decodeFromString(wechatpaySignature));

完整的验签代码

/**

* 我方对响应验签,和应答签名做比较,使用微信平台证书.

*

* @param wechatpaySerial response.headers['Wechatpay-Serial'] 当前使用的微信平台证书序列号

* @param wechatpaySignature response.headers['Wechatpay-Signature'] 微信平台签名

* @param wechatpayTimestamp response.headers['Wechatpay-Timestamp'] 微信服务器的时间戳

* @param wechatpayNonce response.headers['Wechatpay-Nonce'] 微信服务器提供的随机串

* @param body response.body 微信服务器的响应体

* @return the boolean

*/

@SneakyThrows

public boolean responseSignVerify(String wechatpaySerial, String wechatpaySignature, String wechatpayTimestamp, String wechatpayNonce, String body) {

if (CERTIFICATE_MAP.isEmpty() || !CERTIFICATE_MAP.containsKey(wechatpaySerial)) {

refreshCertificate();

}

Certificate certificate = CERTIFICATE_MAP.get(wechatpaySerial);

final String signatureStr = createSign(wechatpayTimestamp, wechatpayNonce, body);

Signature signer = Signature.getInstance("SHA256withRSA");

signer.initVerify(certificate);

signer.update(signatureStr.getBytes(StandardCharsets.UTF_8));

return signer.verify(Base64Utils.decodeFromString(wechatpaySignature));

}

CERTIFICATE_MAP 平台证书容器可参考上一篇文章。

3. 总结

验签通过就说明我们请求的响应来自微信服务器就可以针对结果进行对应的逻辑处理了,微信支付API无论是V2还是V3都包含了使用Api证书对请求进行加签,对响应结果进行验签的流程,十分考验对密码摘要算法的使用,其它就是组织参数调用Http请求。如果你能够掌握这一能力就会在面试中和工作中占到优势。好了今天分享就到这里,多多关注: 码农小胖哥 获取更多实用的编程干货。

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

微信支付服务器验证的java_Java中的微信支付(3):API V3对微信服务器响应进行签名验证...相关推荐

  1. API v3版微信支付平台证书获取与自动更新

    API v3版微信支付平台证书获取与自动更新 关于微信证书 获取平台证书 证书自动更新 首次下载证书 关于微信证书 微信支付开发有两份证书. ♥ 商户证书:商户平台证书私钥可以对请求进行签名,微信服务 ...

  2. 微信扫码 android sdk,H5中js-sdk扫码功能,Android手机微信中无法调用扫码?

    我的H5对接微信JS-SDK中的扫码功能,发现在Android手机微信中无法调用扫码功能,在苹果手机微信中可以使用. 报如下错误: errMsg:scanQRCode:permissi on deni ...

  3. NodeJS 基于API v3 实现微信小程序的支付

    前提 在微信商户平台成为商家,按照官网的文档进行配置,弄好下载证书,将证书复制到后端的项目上 实现过程 GitHub - yangfuhe/node-wxpay: 微信支付APIv3 for node ...

  4. java微信支付验证签名_Java中的微信支付(3):API V3对微信服务器响应进行签名验证...

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

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

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

  6. 服务器客户端对话java_java中的服务器和客户机如何使用

    网络最基本的精神就是让两台机器连接到一起,并相互"交谈"或者"沟通".一旦两台机器都发现了对方,就可以展开一次令人愉快的双向对话.但它们怎样才能"发现 ...

  7. 寻仙有的服务器显示测速中,2018年4月4日1组服务器合并公告

    <寻仙>将于2018年4月4日,对部分服务器进行调优合并.调优合并工作将于4月4日09:00停机维护后进行,预期维护时间为12小时,期间进行调优合并的服务器都将暂时停止服务,如未完成,时间 ...

  8. php微信小程序物流进度推送,微信小程序 消息推送php服务器验证实例详解

    微信小程序 消息推送php服务器验证实例详解 设置页面("设置">>"开发设置"): 1.设置服务器域名 注意http和https协议的不同. 2. ...

  9. 【愚公系列】2022年11月 微信小程序-优购电商项目-商品支付页面

    文章目录 前言 1. 商品⽀付页面设计规范 一.商品支付页面 1.业务逻辑 2.涉及的接口数据 3. 关键技术 二.商品购物车页面相关代码 1.页面代码 2.效果 前言 1. 商品⽀付页面设计规范 第 ...

最新文章

  1. 微信小程序时间戳转化为时间
  2. Java异常的性能分析
  3. 开课吧python学费-分享一个小白也能月赚2万的新技能
  4. [ZJOI2007]仓库建设(斜率优化)
  5. winform datagridview 设置标题
  6. 依赖编译_开源项目的编译优化实践
  7. python文件打包发布(引用的包也可以加进来),打包出错解决了,运行出错解决了...
  8. 产品经理是个实战类科目
  9. Java高并发编程详解系列-线程上下文设计模式及ThreadLocal详解
  10. java 1 0_【Java】1.0 开发环境
  11. python类定义中__init__()_转:python学习——类中为什么要定义__init__()方法
  12. mkpasswd命令
  13. ERROR 1130: Host ’...′ is not allowed to connect to this MySQL server
  14. 负载均衡之让nginx跑起来
  15. python zemax_最新Python中文版发布,跨界程序员零压力学Python之道!(附下载)
  16. [三星6818]gpio模拟spi信号编写门禁卡识别模块驱动
  17. (位于 xx.exe 中)引发的异常
  18. html页面内检索,如何用 javascript 实现html页面的关键字搜索?
  19. 清理C盘的几种方法,帮你解决C盘爆红的烦恼
  20. 科学设置百度网盟到访定向,提升竞价转化率!

热门文章

  1. 查询公司资产数据库中的主机是否在zabbix的监控中
  2. sql server数据库的部署
  3. 2017华南理工华为杯H bx值(容斥问题)
  4. Windows server 2008 R2搭建主域控制器 + 辅域控制器
  5. Java乔晓松-android中调用系统拍照功能并显示拍照的图片
  6. oracle数组的使用
  7. 软件开发工程师--经验之谈
  8. NHibernate源码分析开篇
  9. SQL server 2005 如何批量修改架构名(包括表名和存储过程名) .
  10. 1005 继续(3n+1)猜想(25 分)