支付宝spi接口设计验签和返回结果加签注意点,支付宝使用JSONObject对象

SPI 三方服务接入指南
https://opendocs.alipay.com/isv/spiforisv

服务端实现 Demo
以下 Demo 是通过 Java 实现的 SPI 服务样例,包括验签 支付宝请求报文、业务逻辑处理、商家加签 以及 响应报文构造 的逻辑。
该 Demo 仅供参考,不同语言环境可根据该 Demo 的处理思路自行实现。

@RequestMapping(value  =  "/isv/spi/service")
@ResponseBody
public String spiService(@RequestParam Map < String , String > params ) {
// http响应结果载体
JSONObject result = new JSONObject();
// 业务处理结果载体
JSONObject response = new JSONObject();
// 1、验签支付宝请求报文
boolean isPass = AlipaySignature.rsaCheckV1( params , alipayPublicKey , "UTF-8" , "RSA2" );
if(isPass) {
// 2、验签成功:处理业务逻辑,并构造业务处理结果
response.put("code" , "10000");
response.put("msg" , "Success");
response.put("biz" , "value");
JSONObject person = new JSONObject();
person.put("age" , "18");
person.put("height" , "180");
response.put("person" , person); // response中嵌套复杂类型数据结构场景
} else {
// 验签失败:构造错误码
response.put("code" , "40004");
response.put("msg" , "Business Failed");
response.put("sub_code" , "ISV-VERIFICATION-FAILED");
response.put("sub_msg" , "验签失败");
}
// 3、业务处理结果加签 (可选,查看 服务基础配置 章节)
// contentToSign为 {"code":"10000","msg":"Success","biz":"value","person":{"age":"18","height":"180"}}
String contentToSign = response.toJSONString();
String sign = AlipaySignature.rsaSign(contentToSign,isvPrivateKey ,"UTF-8","RSA2");
// 4、构造http响应结果
result.put("sign" , sign);
//可选,查看 服务基础配置
result.put("response" , response);
// 返回json格式响应报文
return result.toJSONString();
}

扩展:return result.toJSONString(); // resultJson
支付宝拿到这个返回的字符串。如何来验签呢?

//模拟接收端的方式
JSONObject jsonObject = JSONObject.parseObject(resultJson);
String responseJson = jsonObject.getString("response");
String signJson = jsonObject.getString("sign");
System.out.println("responseJson=" + responseJson);
System.out.println("signJson=" + signJson); boolean isPass = AlipaySignature.rsaCheck(responseJson, signJson,pub_key, "UTF-8", "RSA2");
System.out.println("isPass=" + isPass);

需要注意点:
1. 接口使用Map来接收 @RequestParam Map < String , String > params
// 1、验签支付宝请求报文
boolean isPass = AlipaySignature.rsaCheckV1( params , alipayPublicKey , "UTF-8" , "RSA2" );
你先验签,然后再解析,验证不用管map是啥,我们传什么你们正常验证就行。而不是使用对象或单个字段来接收,无法确保接收的数据是全部的。不然影响签名。
支付宝调用过来的:是支付宝使用支付宝私钥签名,商户端使用支付宝公钥验签。

同理:如果是商户对结果加签,是使用商户的私钥签名,支付宝接收到后使用商户的公钥来验签。

使用map获取签名的字符串方法:String content = AlipaySignature.getSignCheckContentV1(params);
//map的加签字符是可以固定顺序的。同理:json字符串固定顺序只能通过使用相同的对象(JSONObject)来转换达到字符相同。

 public static String getSignCheckContentV1(Map<String, String> params) {
if (params == null) {
return null;
} params.remove("sign");
params.remove("sign_type"); StringBuilder content = new StringBuilder();
List<String> keys = new ArrayList<String>(params.keySet());
Collections.sort(keys); int index = 0;
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (StringUtils.areNotEmpty(key, value)) {
content.append((index == 0 ? "" : "&") + key + "=" + value);
index++;
}
} return content.toString();
}

2. 验签报错,是因为从钉钉里面复制的sign是url编码后的。 而实际接口是未url编码的字符串。
spiServiceCreate occur exception : com.alipay.api.AlipayApiException: RSA2验签遭遇异常,请检查公钥格式或签名是否正确。Signature length not correct: got 267 but was expecting 256
对比看了下,这个日志里面的sign是url编码过的,而在接口请求过来的sign是没有url编码。实际在验证签名的时候,不能使用编码后的字符,如果已经编码过,需要解码。

3.验签用公钥。加签名用私钥。需要注意两端的公私钥,公钥是一致的,如果不一致,则验签不通过。

4.返回结果key参数去掉。无需返回,接口文档中是有这个。 实际会影响对方验证签名。
错误格式,不需要key,影响验签:

{
"response" :{
"code" : "10000" ,
"msg" : "Success" ,
"key" : "value"
},
"sign" : "xxx"
}

正确格式:

{
"response" :{
"code" : "10000" ,
"msg" : "Success" ,
"name" : "lisi"
},
"sign" : "TqnBnkILs86FJWRqWWZptqIpSKLIp2vnwod177h7GLyWuLhzgRHpXgXd8GoD4flyHrHBTycQdiUjWw6VqCE5rYHrJU3iYqI1e0MLlhCb"

数据格式:

response JSONObject
code String
msg String
name String 业务字段
sign String

5.机构合约编号最好用个规范字符串
最好是日期开头20240613+业务标识+业务号+随机+这种有点业务语义的

6.Gson == 转义成了 \u003d\u003d, 需要使用 fastJson,涉及到url编码的字符串尽量不使用Gson。

7.需要对比一下,json字符串里面的字段的顺序。 顺序也会影响签名。关键,比如:123,132,321是3个不同的签名字符。
JSON.toJSONString
String contentToSign = jsonObject2.toJSONString();
测试发现:上面两个转换成json字符串,实际上json字符串中的字段顺序不一致,导致签名和验签的contentToSign不一致,验签错误。
结论:支付宝验签是使用的:JSONObject方式来转的json,所以商户端也需要使用JSONObject来转json字符串。

8. response对象是JSONObject对象,而不是String json字符串。
JSONObject jsonObject = (JSONObject) JSON.toJSON(realResponse); //对象转JSONObject
//spiBaseResponseVo.setResponse(JSON.toJSONString(realResponse)); //错误

//测试代码(解决方案,使用JSONObject,同理:项目中可以使用业务VO对象,在签名获取contentToSign字符串的时候,将业务对象转换为JSONObject也可以解决。)
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.AlipaySignature; public class AlipaySignature5Test {
//商户私钥
private static String prv_key = "商户私钥";
//商户公钥
private static String pub_key = "商户公钥"; public static void main(String[] args) throws Exception{ // http响应结果载体
JSONObject result = new JSONObject();
// 业务处理结果载体
JSONObject response = new JSONObject(); response.put("code" , "10000");
response.put("msg" , "Success");
response.put("inst_ser_contract_no" , "20240614Test123456789");
// 3、业务处理结果加签 (可选,查看 服务基础配置 章节)
// contentToSign为 {"code":"10000","msg":"Success","biz":"value","person":{"age":"18","height":"180"}}
String contentToSign = response.toJSONString();
System.out.println("content=" + contentToSign);
String sign2 = AlipaySignature.rsaSign(contentToSign,prv_key ,"UTF-8","RSA2");
System.out.println("sign2=" + sign2); // 4、构造http响应结果
result.put("sign" , sign2);
//可选,查看 服务基础配置
result.put("response" , response);
// 返回json格式响应报文
String resultJson = result.toJSONString();
System.out.println("接口返回的结果=" + resultJson);
//直接拿resultJson验签会返回false
//boolean isPass = AlipaySignature.rsaCheck(resultJson, sign2,pub_key, "UTF-8", "RSA2"); //接收端的方式
JSONObject jsonObject = JSONObject.parseObject(resultJson);
String responseJson = jsonObject.getString("response");
String signJson = jsonObject.getString("sign");
System.out.println("responseJson=" + responseJson);
System.out.println("signJson=" + signJson); boolean isPass = AlipaySignature.rsaCheck(responseJson, signJson,pub_key, "UTF-8", "RSA2");
System.out.println("isPass=" + isPass);
}
}
//测试代码(解决方案,使用JSONObject,同理:项目中可以使用业务VO对象,在签名获取contentToSign字符串的时候,将业务对象转换为JSONObject也可以解决。)
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.internal.util.AlipaySignature; public class AlipaySignature5Test {
//商户私钥
private static String prv_key = "商户私钥";
//商户公钥
private static String pub_key = "商户公钥"; public static void main(String[] args) throws Exception{ // http响应结果载体
JSONObject result = new JSONObject();
// 业务处理结果载体
JSONObject response = new JSONObject(); response.put("code" , "10000");
response.put("msg" , "Success");
response.put("inst_ser_contract_no" , "20240614Test123456789");
// 3、业务处理结果加签 (可选,查看 服务基础配置 章节)
// contentToSign为 {"code":"10000","msg":"Success","biz":"value","person":{"age":"18","height":"180"}}
String contentToSign = response.toJSONString();
System.out.println("content=" + contentToSign);
String sign2 = AlipaySignature.rsaSign(contentToSign,prv_key ,"UTF-8","RSA2");
System.out.println("sign2=" + sign2); // 4、构造http响应结果
result.put("sign" , sign2);
//可选,查看 服务基础配置
result.put("response" , response);
// 返回json格式响应报文
String resultJson = result.toJSONString();
System.out.println("接口返回的结果=" + resultJson);
//直接拿resultJson验签会返回false
//boolean isPass = AlipaySignature.rsaCheck(resultJson, sign2,pub_key, "UTF-8", "RSA2"); //接收端的方式
JSONObject jsonObject = JSONObject.parseObject(resultJson);
String responseJson = jsonObject.getString("response");
String signJson = jsonObject.getString("sign");
System.out.println("responseJson=" + responseJson);
System.out.println("signJson=" + signJson); boolean isPass = AlipaySignature.rsaCheck(responseJson, signJson,pub_key, "UTF-8", "RSA2");
System.out.println("isPass=" + isPass);
}
}

支付宝spi接口设计验签和返回结果加签注意点,支付宝使用JSONObject对象的更多相关文章

  1. Django 支付宝付款接口的使用

    我们在开发的过程中经常会碰到调用微信或者支付宝接口进行付款,付款完成之后,如果用户绑定了我的账号,我只要有活动了,就要给这个关注我的用户推动消息,让用户知道,比如说,我们经常会关注一些公众号,然后这些 ...

  2. Http请求加签、验证操作

    加签.验签的作用 常见的http请求交互过程中,请求参数通过url或者request body等形式传输.但是由于http请求的开放性,使得请求参数很容易被拦截篡改.因此,需要对请求参数进行加签,然后 ...

  3. Slickflow.NET 开源工作流引擎基础介绍(五) -- 会签加签高级特性介绍

    前言:会签和加签是常见审批流程模式,在引擎中,对这两种流程模式做了分别定义和实现,其中也用到了Workflow Pattern的Multiple Instance(多实例) . 1. 会签和加签的定义 ...

  4. 工作流一期上线原创小故事——【加签】OR【不准】

    亲!您有过选择[加签]还是审核[不准]的烦恼吗? 加签分为:向前加签和向后加签,这个相信大家都很熟悉了吧. 审核分为:准和不准,就是√和×,这个相信大家也很熟悉了. 提示①:相邻的2个人审核时,如果意 ...

  5. Java Http接口加签、验签操作方法

    1.业务背景 最近接触了一些电商业务,发现在处理电商业务接口时,比如淘宝.支付类接口,接口双方为了确保数据参数在传输过程中未经过篡改,都需要对接口数据进行加签,然后在接口服务器端对接口参数进行验签,确 ...

  6. 25-javaweb接入支付宝支付接口

    想熟悉支付宝接口支付,后面可能会用,不如在课设中试试手.好吧听说支付宝不微信支付要简单些,就拿支付宝的先练下手吧. 基本学习流程,百度一下,找篇博客看下. 推荐下面这个篇博客,讲的挺好的,复制过来. ...

  7. Android开发---支付宝功能接口(支付功能)(转载!)

    最近在做一个关于购物商城的项目,项目里面付款这块我选的是调用支付宝的接口,因为用的人比较多. 在网上搜索了以下,有很多这方面的教程,但大部分教程过于陈旧,而且描述的过于简单.而且支付宝提供的接口一直在 ...

  8. RSA加密解密及RSA加签验签

    RSA安全性应用场景说明 在刚接触RSA的时候,会混淆RSA加密解密和RSA加签验签的概念.简单来说加密解密是公钥加密私钥解密,持有公钥(多人持有)可以对数据加密,但是只有持有私钥(一人持有)才可以解 ...

  9. python调用支付宝支付接口

    python调用支付宝支付接口详细示例—附带Django demo代码   项目演示: 一.输入金额 二.跳转到支付宝付款 三.支付成功 四.跳转回自己网站 在使用支付宝接口的前期准备: 1.支付宝公 ...

  10. python调用支付宝支付接口详细示例—附带Django demo代码

    项目演示: 一.输入金额 二.跳转到支付宝付款 三.支付成功 四.跳转回自己网站 在使用支付宝接口的前期准备: 1.支付宝公钥 2.应用公钥 3.应用私钥 4.APPID 5.Django 1.11. ...

随机推荐

  1. NBF事件中心架构设计与实现

    ​简介:NBF是阿里巴巴供应链中台的基础技术团队打造的一个技术PaaS平台,她提供了微服务FaaS框架,低代码平台和中台基础设施等一系列的PaaS产品,旨在帮助业务伙伴快速复用和扩展中台能力,提升研发 ...

  2. [FAQ] Windows 终端 git status 不识别文件名大小写的修改

      当我们修改了文件名的大小写,git status 显示没有文件改动. 出现这种情况,首先看一下 git 的配置项是否忽略了文件问大小写: $ git config core.ignorecase ...

  3. [FAQ] 你所看过的 APP 流氓提示语有哪些

    分享案例来自产品:网抑云. 当你要进行一些常规操作,比如评论时,进行弹窗伺候: |----------------------| |       | |   为提高您的账号安全性,请先绑定手机号   ...

  4. [FAQ] Large files detected. You may want to try Git Large File Storage

    Git 提交文件大于 100M 时提示需要使用 Git LFS. Ubuntu 安装示例: $ curl -s https://packagecloud.io/install/repositories ...

  5. [PHP] 浅谈 Laravel 三大验证方式的区别, auth:api, passport, auth:airlock

    auth:api 最先出来,提供了最简单和最实用的方式进行 api 身份校验. 关于它的含义和用法你可以参考以下两篇: 浅谈 Laravel Authentication 的 auth:api 浅谈 ...

  6. 15.prometheus之pushgateway自定义监控

    一.Pushgateway 1.Pushgateway简介 Pushgateway 是 Prometheus 生态中一个重要工具,使用它的原因主要是: ● Prometheus 采用 pull 模式, ...

  7. vue3 快速入门系列 —— 状态管理 pinia

    其他章节请看: vue3 快速入门 系列 pinia vue3 状态管理这里选择 pinia. 虽然 vuex4 已支持 Vue 3 的 Composition API,但是 vue3 官网推荐新的应 ...

  8. Linux中的man page指令

    以Linux上的date命令为例,在控制台输入 man date,将会展示如下界面: [vbird@www ~]$ man date DATE(1) User Commands DATE(1) # 请 ...

  9. ContextCapture-硬件配置推荐

    ContextCapture倾斜摄影的空三计算.三维建模应用.非常耗费硬件资源,适当调整硬件配置,可以显著提高模型处理时间. 硬件常见问题 随着倾斜摄影建模算法成熟,应用越来越广泛,数据量越来越大,需 ...

  10. RMBG1.4服务器部署指南

    近期,一家AIGC公司BRIA开源了一个出圈的模型:RMBG-1.4,它可以实现高质量地一键去除图片中的背景.下面是一些具体的例子,可以看到这个模型可以实现非常精细的"抠图". R ...