支付宝 v3 验签如何实现
上次给大家介绍了 支付宝 v3 自签名如何实现,这次顺便再把验签也写一下。

为什么要验签
说起为什么要验签,如果要详细一点解释的话,可以写很多很多......
我们就简单一点来解释:验签可以证明接收到的信息是支付宝给我的,不是被人中途拦截篡改数据之后再发给我的。
支付宝的通知分为 「同步通知 」和 「异步通知 」:
- 「同步通知 」就是我们请求支付宝之后,支付宝返回的数据。
- 「异步通知 」是到达某些条件之后,支付宝主动发的;更详细内容可以参考之前我写的 [手把手|支付宝异步通知如何使用]。
对于这两种通知我们都需要进行验签处理,才能保证数据的准确性!(️ 很重要!!)
其实支付宝给的 SDK 里面也封装了验签的方法,并且对同步通知都经过了验签的处理,同步验签不过的话,接口会直接抛出异常 [sign check fail: check Sign and Data Fail]。
另外 v3 SDK 里面提供的验签方法名跟 v2 版本是一样的,大家不想麻烦的话可以直接查看 [SDK如何实现验签]。
(大家凑合看,v3 版本好像还没有完整的验签示例代码,也可能是我没找到 )
虽然给了这么多简单的方法,但是我就是要自!己!写!一!遍!╭(╯^╰)╮
如何验签
验签的流程比加签要简单一点,下面用支付宝同步通知的数据做验签例子
步骤一、接收支付宝返回的信息
首先就是要接收到支付宝返回的信息,因为是同步验签的数据,直接拿之前自签名的代码改一下
验签我们所需要的数据有:
- aliapy-signature:支付宝生成的签名内容。
- alipay-timestamp:支付宝应答时间戳。
- alipay-nonce:支付宝应答随机串。
- httpResponseBody:响应报文内容,自签名的 resData 数据。
接收代码
//获取响应的请求头head
Header[] responseHeader = response.getAllHeaders();
//待验签数据head:aliapy-signature、alipay-timestamp、alipay-nonce
String alipaysignature = response.getFirstHeader("alipay-signature").getValue();
String alipaytimestamp = response.getFirstHeader("alipay-timestamp").getValue();
String alipaynonce = response.getFirstHeader("alipay-nonce").getValue();
获取到的响应值
httpResponseBody:{"out_trade_no":"20181128763521373251698","qr_code":"https://qr.alipay.com/bax04870evi3w2dlaeai2502"}
aliapy-signature:M/6yx2OajiQD0mM9Tk9ShsduFERtmj+xI0BN8QiZk8BMUCvMQCne1n/VIbMZ738k4No8nsE1DC0saPe2NqtmgxC3B+TmWgrhJ+4JOVEc7K4/LcIDWN2PaPCw5g5+oUQRIGCbo0+f9yqSew4NwETV2RiVIw91q+kJ4OeIpauSnGQAuwOxqciDM52k7gUhij8G+evhK7xn6TNhiQgRk0RjkyhEEp/00lYb5xI2d9Oj5KgsDC9KTRo9SO0SJaH0SbfNHU40XUkkomuj6jiOEeccfB6Fofzq5jfL3u24Ev9SxTDf2kYZzffShLrYhlrI8947VqC3h8/F6O8y4K/PQl3LCw==
alipay-timestamp:1703576825544
alipay-nonce:73b3422127c9996ad405e77091eef6f4
包含之前自签名的完整代码(仅供参考)
public class V3HttpPostTest {
public static void main(String args[]) throws Exception {
// 发送请求的url
String url = "https://openapi.alipay.com/v3/alipay/trade/precreate";
// 发送请求的内容
String content = "{\"out_trade_no\":\"20181128763521373251698\",\"total_amount\":\"1\",\"subject\":\"123\",\"body\":\"body\"}";
String chearset = "utf-8";
// 创建请求对象:post或者get
HttpPost httpPost = new HttpPost(url);
// httpClient实例化
CloseableHttpClient httpClient = HttpClients.createDefault();
// 设置类型
// "application/x-www-form-urlencoded","application/json"、multipart/form-data、text/xml
httpPost.setHeader("Content-Type", "application/json");
// 调用方的requestId,用于定位一次请求,需要每次请求保持唯一。
httpPost.setHeader("alipay-request-id", "32432432432423421");
httpPost.setHeader("authorization",
"ALIPAY-SHA256withRSA app_id=2021111111111122,timestamp=1702452177941,nonce=3246658768654544,sign=WDF6pS2qK/kEZnsJDMrhNmd/z82ClZ+VMohYxIUs3MZ2j0m+4reQtSBGa6mZyA5ffbIPPvZTRO+1DLEuuCvZRMQGK3okYSA/ASP7GEqfCDeKmkqzKV2kWrmftNfO+EiIiCnsiyJG4SQ9G7s0OtmCT6wVkphW9wgk7mfUoF5a+Wo3kzvEur3U+7ZfSgLa4HXQG2xE+z7BjmHG8j1qVoVa/3TR1lVBAqOwkodZ9cSPKceK2RxaPkk8gsFbofbuARl5xBqDwkS2caTQu27+DLXT/QJOHRHRw5VtH9v8B7nT+nrijFjktm6hD7aIHuPon6TtEgnbtWltRizEZldh+Fo1Eg==");
// 支付宝根证书序列号,使用证书模式时,需要传递该值
// httpPost.setHeader("alipay-root-cert-sn", "");
// 组织数据
StringEntity se = null;
try {
se = new StringEntity(content);
// 设置编码格式
se.setContentEncoding(chearset);
// 设置数据类型
se.setContentType("application/json");
// post请求,将请求体填充进httpPost
httpPost.setEntity(se);
// 通过执行httpPost获取实例
HttpResponse response = httpClient.execute(httpPost);
HttpEntity entity = response.getEntity();
String resData = EntityUtils.toString(entity);
System.out.println("httpResponseBody:" + resData);
//获取响应的请求头head
Header[] responseHeader = response.getAllHeaders();
//待验签数据head:aliapy-signature、alipay-timestamp、alipay-nonce
String alipaysignature = response.getFirstHeader("alipay-signature").getValue();
String alipaytimestamp = response.getFirstHeader("alipay-timestamp").getValue();
String alipaynonce = response.getFirstHeader("alipay-nonce").getValue();
System.out.println("aliapy-signature:" + alipaysignature);
System.out.println("alipay-timestamp:" + alipaytimestamp);
System.out.println("alipay-nonce:" + alipaynonce);
// 关闭httpClient资源
httpClient.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
步骤二、拼接待验签内容
接收到响应数据之后,我们需要按照
${alipay-timestamp}\n
${alipay-nonce}\n
${httpResponseBody}\n
规则,将数据组装起来。
content 组装示例
【注意:\n 不要丢!】
String content = alipaytimestamp + "\n" + alipaynonce + "\n" + httpResponseBody + "\n";
返回值
1703576825544
73b3422127c9996ad405e77091eef6f4
{"out_trade_no":"20181128763521373251698","qr_code":"https://qr.alipay.com/bax08770vkyzjc0is6ep25ed"}
步骤三、进行签名比对
组装完待验签内容之后,我们就可以将数据进行验签了,其中用到的参数有:
- content:上一步获取到的内容。
- alipaysignature:第一步获取到的 alipaysignature。
- publicKey:为支付宝公钥,在支付宝平台上传应用公钥后获取,参考 [如何获取支付宝公钥]。
- charset:编码格式,代码中用的是 UTF-8。
验签代码
private static boolean doVerify(String content, String alipaysignature, String publicKey, String charset) throws Exception {
try {
byte[] encodedKey = publicKey.getBytes();
encodedKey = Base64.getDecoder().decode(encodedKey);
PublicKey pubKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(encodedKey));
java.security.Signature signature = java.security.Signature.getInstance("SHA256withRSA");
signature.initVerify(pubKey);
signature.update(content.getBytes(charset));
boolean signVerified = signature.verify(Base64.getDecoder().decode(alipaysignature.getBytes()))
System.out.println("signVerified:" + signVerified);
return falg;
} catch (Exception e) {
String errorMessage = "验签失败,请检查公钥格式是否正确。content=" + content + " publicKey=" + publicKey + " reason="
+ e.getMessage();
throw new Exception(errorMessage);
}
}
返回值
signVerified:true
只有返回 true 才能说明验签是通过的。
写在最后
v3 验签写完之后,可以看到其实跟 v2 的验签方法没有什么区别,最大的不同点在于待验签内容,大家都可以试试看,还是挺简单的。
支付宝 v3 验签如何实现的更多相关文章
- 【支付宝】"验签出错,sign值与sign_type参数指定的签名类型不一致:sign_type参数值为RSA,您实际用的签名类型可能是RSA2"
问题定位:从描述就可以看的出来了,你现在sign_type是 RSA类型的,要改成跟你现在用的签名类型一致的类型,也就是 要改为 RSA2 PHP为例 // 新版只支持此种签名方式 商户生成签名字符 ...
- 微信,支付宝,支付异步通知验签,notify_url
在支付接口开发中 ,当用户支付完成之后,阿里或者微信会向我们服务器发送一个支付结果的通知,里边带有一系列参数:其中特殊的是签名类型,和签名(他们根据这些参数做出来的签名). 我们的得到这些参数之后要去 ...
- NodeJs支付宝移动支付签名及验签
非常感谢 :http://www.jianshu.com/p/8513e995ff3a?utm_campaign=hugo&utm_medium=reader_share&utm_co ...
- 支付宝App支付签名和验签
代码: using CMS.Utility.ReturnResult; using OAuthWebAPI.Package; using Common; using System; using Sys ...
- 支付宝2018年最新SDK对接验签的问题
下单加签 AopUtils.SignAopRequest(sortedTxtParams,应用私钥, "UTF-8", false, "RSA2"); 异步回调 ...
- APP支付-》支付宝RSA2->支付与验签
第一次配置支付宝,按照官网示例搞了一天,走不通.经过两天的踩坑,百度了大神的代码,支付宝终于可以了. 1:下载这是官网的最新SDK 2:配置SDK,添加命名空间 AopClient.php文件: Si ...
- 支付宝支付集成中:refund_fastpay_by_platform_nopwd接口服务器通知验签不通过
在做p2p配资平台,也就是公司的项目,遇到了一个问题:refund_fastpay_by_platform_nopwd接口服务器通知验签不通过 下面是实录: 通知服务器的POST过来的数据: 1.si ...
- Delphi支付宝支付【支持SHA1WithRSA(RSA)和SHA256WithRSA(RSA2)签名与验签】
作者QQ:(648437169) 点击下载➨Delphi支付宝支付 支付宝支付api文档 [Delphi支付宝支付]支持条码支付.扫码支付.交易查询.交易退款.退款查询.交易撤 ...
- 支付宝支付回调方法RSA2验签失败处理方法
支付宝支付签名方式RSA2生成支付时使用的是支付宝公钥和应用私钥, 而不是应用公钥,支付宝公钥的生成是根据上传应用公钥而变动的, 所以在做回调的时候参数ALIPAY_PUBLIC_KEY也需要传支付宝 ...
- .NET RSA解密、签名、验签
using System; using System.Collections.Generic; using System.Text; using System.IO; using System.Sec ...
随机推荐
- Asp-Net-Core开发笔记:FrameworkDependent搭配docker部署
前言 之前我写过一篇使用 docker 部署 AspNetCore 应用的文章,这种方式搭配 CICD 非常方便, build 之后 push 到私有的 dockerhub ,在生产服务器上 pull ...
- 设备维修保养通知:如何使用API接口发送通知给相关人员
在设备维修保养管理中,及时通知相关人员是确保设备得到及时维护的关键.API接口提供了一个方便的方式来自动发送维修保养通知,以确保工作流程的顺利进行.本文将详细介绍如何使用成熟的API接口来发送设备维修 ...
- Node.js 20 —— 几个令人大开眼界的特性
前言:欢迎来到 Node.js 20 Node.js 20 已经发布,带来了创新和激动人心的新时代.这个开创性的版本于2023年4月18日首次亮相,并将在2023年10月发布长期支持(LTS)版本,并 ...
- 圆柱坐标系(Cylindrical Coordinate System)
参考:维基百科 圆柱坐标系(英语:cylindrical coordinate system)是一种三维坐标系统.它是二维极坐标系往 z-轴的延伸.添加的第三个坐标 \(z\) 专门用来表示 P 点离 ...
- 再谈http请求调用(Post与Get),项目研发的核心一环
支持.Net Core(2.0及以上)与.Net Framework(4.0及以上) [目录] 前言 Post请求 Get请求 与其它工具的比较 1[前言] http请求调用是开发中经常会用到的功能. ...
- tiptopGP5.2链接所有表或报不存在函数处理
修改交易的表时需要特别注意,改完要关联所有有关的表r.rb.rb pja_file 当链接提示不存在的函数调用,又无法确定具体是那个关联程序时, 可以在本函数内先定义这个报错的函数,重新链接时,系统会 ...
- 前端CodeReivew实践
把Code Review变成一种开发文化而不仅仅是一种制度 把Code Review 作为开发流程的必选项后,不代表Code Review这件事就可以执行的很好,因为Code Review 的执行,很 ...
- 立方骑士(lgP7354)
来水篇题解((( 图炸了,去洛谷博客看吧. 注:在本篇题解中, \(K\) 表示国王, \(N\) 表示骑士,不同颜色的 \(X\) 表示该位置国王可以达到,且被与之相同颜色的骑士封锁.方法不唯一,图 ...
- Python 利用pandas和mysql-connector获取Excel数据写入到MySQL数据库
如何将Excel数据插入到MySQL数据库中 在实际应用中,我们可能需要将Excel表格中的数据导入到MySQL数据库中,以便于进行进一步的数据分析和处理.本文将介绍如何使用Python将Excel表 ...
- 查找数组中第K大的元素
要查找一个数组中的第 K 大元素,有多种方法可以实现,其中常用的方法是使用分治算法或快速选择算法,这两种方法的时间复杂度到时候O(n). 快速选择算法示例: package main import & ...