Java中的微信支付(3):API V3对微信服务器响应进行签名验证
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中的微信支付(3):API V3对微信服务器响应进行签名验证的更多相关文章
- 微信支付开发(12) 认清微信支付v2和v3
微信支付现在分为v2版和v3版 2014年9月10号之前申请的为v2版,之后申请的为v3版. V2版中的参数有AppIDAppSecret支付专用签名串PaySignKey商户号PartnerID初始 ...
- 微信支付之h5方式(非微信内置浏览器中支付)
这两天完成了公司网站手机和PC端的支付对接,就是支付宝和微信. 对接完后有所感触,我们来聊一聊,微信支付的坑,为什么这么说呢,因为我在对接完支付宝后是很愉快的,基本上在demo上稍加修改就ok了, 对 ...
- iOS中 最新微信支付/最全的微信支付教程详解 韩俊强的博客
每日更新关注:http://weibo.com/hanjunqiang 新浪微博! 亲们, 首先让我们来看一下微信支付的流程吧. 1. 注册微信开放平台,创建应用获取appid,appSecret, ...
- 微信支付之01------获取订单微信支付二维码的接口------Java实现
[ 前言:以前写过一个获取微信二维码支付的接口,发现最近公司新开的项目会经常用到,现在我又翻出代码看了一遍,觉得还是把整个代码流程记下来的好 ] 借鉴博客: 他这篇博客写得不错,挺全的:https:/ ...
- iOS中 最新微信支付/最全的微信支付教程具体解释 韩俊强的博客
亲们, 首先让我们来看一下微信支付的流程吧. 1. 注冊微信开放平台,创建应用获取appid,appSecret,申请支付功能,申请成功之后会返回一些參数. 2. 下载微信支付sdk 3. clien ...
- JAVA微信支付——企业付款(企业向微信用户个人付款、转账)
本地开发环境支付回调调试方法可以参考:https://www.cnblogs.com/pxblog/p/11623053.html 需要自行引入相关依赖 官方文档地址:https://pay.weix ...
- 微信支付官方SDK V3 .NET版的坑
但是支付成功后却不能正确的执行支付结果js回调函数.看看其页面的点击事件是放在asp:Button上面的.我们知道在asp.net webform中,按钮的点击是有页面回调后台的.也就是其实点击了之后 ...
- 微信支付JS API使用心得
微信的接口真的很坑爹,只返回成功或失败,从来不会告诉你为什么失败.这个微信支付的js接口也是调了一个下午才成功,期间踩了不少坑,在这里总结一下,而且把支付接口封装成了一个js文件,这样以后调用就很方便 ...
- ThinkPHP 5 整合支付宝微信支付(支付宝H5,微信H5、APP支付、公众号支付)
因项目没有PC站所以没有写电脑网站支付. Pay.php支付控制器 <?php // +----------------------------------------------------- ...
随机推荐
- Django新手图文入门教程
版权所有,转载需注明来源! 本文是广受大家欢迎的<Django1.10新手图文入门教程>的2.1版本升级篇,原1.10版本传送门点击我 本文面向有一些的Python基础,但刚接触web框架 ...
- C++逐字输出函数
void fun(string a) { for(int i=0;i<a.length();i++) { cout<<a[i]; usleep(10000); } cout<& ...
- 基于Huggingface使用BERT进行文本分类的fine-tuning
随着BERT大火之后,很多BERT的变种,这里借用Huggingface工具来简单实现一个文本分类,从而进一步通过Huggingface来认识BERT的工程上的实现方法. 1.load data tr ...
- C++中头文件简介(stdio.h & chrono)
参考: 1. https://baike.baidu.com/item/stdio.h 2. https://www.cnblogs.com/jwk000/p/3560086.html 1. stdi ...
- 【学习笔记】Polya定理
笔者经多番周折终于看懂了\(\text{Burnside}\)定理和\(\text{Polya}\)定理,特来写一篇学习笔记来记录一下. 群定义 定义:群\((G,·)\)是一个集合与一个运算·所定义 ...
- 【比赛记录】8.21 div2
A 选择一个点\(B(x,0)\)使得\(|dis(A,B)-x|=k.\) 题目实际上就是找到一个最接近\(n\)的数,使得它可以分成两个数\(a,b,\)使\(a-b=k.\) 我们考虑先分成一个 ...
- 【题解】CF1375D Replace by MEX
\(\color{purple}{Link}\) \(\text{Solution:}\) 观察到题目要求操作次数不超过\(2n,\)且不必最小化操作次数,所以一定是构造题. 考虑将序列转化为\([0 ...
- C# 中 System.Range 结构体
翻译自 John Demetriou 2020年4月6日 的文章 <C# 8 Is Introducing Ranges> 我们之前讨论过的 C# 中的一个特性 System.Index ...
- linux 虚拟机下 安装redis
虚拟机安装linux,打开,挂起就好: 使用ssh连接,这里使用的是Moba Xterm 可以ssh 可以ftp 满足你的日常开发所需,开发必备.每个人都有自己顺手的工具,你喜欢就好 虚拟机挂一边就 ...
- Java工程师应该掌握的知识,按重要程度排出六个阶段如下
第一阶段:计算机组成原理.数据结构和算法.网络通信原理.操作系统原理: 第二阶段:Java基础.JVM内存模型和GC算法.JVM性能调优.JDK工具.设计模式: 第三阶段:Spring系列.Myb ...