今天在看文档的时候,发现支付宝新出了一个 v3 版本的接口调用方式,感觉有点意思,花了点时间研究了下这个版本要怎么实现自签名,大家有兴趣可以看看。

什么是支付宝 API v3 版本?

官网上给的解释是基于 OAS3.0 API 规范,支付宝做了相应的 API 升级(v3),在开发体验上进行了重点优化。

与之前支付宝 API 的主要区别有几条:

  • 使用 RESTful 设计风格,并通过 OpenAPI 规范(OAS)描述接口。
  • 使用 JSON 作为数据交互的格式,不再使用 XML 和表单格式。
  • 简化加验签逻辑,对 HTTP 报文整体进行签名。
  • 简化加解密、文件上传等规范。

更多内容及详细介绍可直接参考 v3 协议简介

其实之前也没有 v2 的概念,不过根据对文档整体的理解来看,v2 版本的概念应该就是之前调用的 通用版本 Easy 版本 。

两个版本的差异可以参考下方表格:

顺便提一句,通用版目前是我用的最多的方式,主要是用习惯了不想改(可不是因为偷懒_(:з」∠)_不过新版方式后面也可以试一下看看。

PS:通用版自签名的方法可以参考:[SDK 如何实现签名],SDK 接口调用方式参考:[代码示例]。

如何对接v3版本

v3 版本比起 v2 版本来说 改变的地方还是挺多的,最大的改变就是请求的方式,由原本的 RPC 风格切换成了RESTful

下面我们就来看看 v3 版本自签名是如何调用的。

下面以 统一收单交易支付接口 为例。

步骤一:构造 authString

authString 也就是 v3 版本新加的身份鉴权信息。

需要用到的参数有:

  • app_id:开放平台颁发的应用 id。
  • timestamp:Unix 时间戳,精确到毫秒。
  • nonce:自定义参数,自己生成唯一性字符串,每次请求要保证唯一。

组装示例

long Unix=date.getTime();
String authString= "app_id="+app_id+",timestamp="+Unix+",nonce=3246658768654544";

authString生成内容

app_id=2014111111111122,timestamp=1702452177941,nonce=3246658768654544

步骤二:拼接待签名字符串

需要用到的参数有:

  • authString:上一步返回。
  • httpMethod:本次请求的 http 方法,例如 GET\POST\PUT。
  • httpReuqestUrl:这个从对应接口文档请求 url 中拿,不包含域名值。
  • httpRequestBody:本次请求的 body 内容;GET方式请求时,入参空字符串。

注意:下方代码示例中的 \n 千万不能丢!!!不然验签通过不了的QAQ

组装示例

String httpMethod="POST";
String httpReuqestUrl= "/v3/alipay/trade/precreate";
String httpRequestBody="{\"out_trade_no\":\"20181128763521373251698\",\"total_amount\":\"1\",\"subject\":\"123\",\"body\":\"body\"}";
String content=authString+"\n"+httpMethod+"\n"+httpReuqestUrl+"\n"+httpRequestBody+"\n";
System.out.println("content:"+"\n"+content);

返回内容

app_id=2021111111111122,timestamp=1702452177941,nonce=3246658768654544
POST
/v3/alipay/trade/precreate
{"out_trade_no":"20181128763521373251698","total_amount":"1","subject":"123","body":"body"}

步骤三:生成 sign

需要用到的参数有:

  • content:上一步返回。
  • privateKey:应用私钥,如何获取参考[如何获取商户私钥]。
  • charset:编码格式。

加签方式这边我想吐槽下:文档上加密方式说是支持 SHA256withRSA 和 SM3WithSM2 两种,但是能用国密加签方式为什么不给我国密配置入口哇,不给入口说支持都是耍流氓啊 ……

签名代码

 private static String doSign(String content,String privateKey,String charset) throws ApiException {
try {
byte[] encodedKey = privateKey.getBytes();
encodedKey = Base64.getDecoder().decode(encodedKey); PrivateKey priKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(encodedKey)); Signature signature = Signature.getInstance("SHA256WithRSA");
signature.initSign(priKey);
signature.update(content.getBytes(charset));
byte[] signed = signature.sign();
return new String(Base64.getEncoder().encode(signed));
} catch (Exception e) {
String errorMessage = "签名遭遇异常,请检查私钥格式是否正确。content=" + content + " privateKeySize=" + privateKey + " reason=" + e.getMessage();
throw new ApiException(errorMessage);
}
}

返回 sign 值

sign:WDF6pS2qK/kEZnsJDMrhNmd/z82ClZ+VMohYxIUs3MZ2j0m+4reQtSBGa6mZyA5ffbIPPvZTRO+1DLEuuCvZRMQGK3okYSA/ASP7GEqfCDeKmkqzKV2kWrmftNfO+EiIiCnsiyJG4SQ9G7s0OtmCT6wVkphW9wgk7mfUoF5a+Wo3kzvEur3U+7ZfSgLa4HXQG2xE+z7BjmHG8j1qVoVa/3TR1lVBAqOwkodZ9cSPKceK2RxaPkk8gsFbofbuARl5xBqDwkS2caTQu27+DLXT/QJOHRHRw5VtH9v8B7nT+nrijFjktm6hD7aIHuPon6TtEgnbtWltRizEZldh+Fo1Eg==

步骤四:发起请求

需要注意的参数:

  • url:文档中的「请求 url」。
  • Content-Type:数据类型。
  • alipay-request-id:自定义参数,保证唯一就可以。
  • authorization:${签名算法} ${authString},sign=${signature}。

注意:上方代码 authorization 中的空格不要丢!!

例如

ALIPAY-SHA256withRSA app_id=2014111111111122,timestamp=1702452177941,nonce=3246658768654544,sign=WDF6pS2qK/kEZnsJDMrhNmd/z82ClZ+VMohYxIUs3MZ2j0m+4reQtSBGa6mZyA5ffbIPPvZTRO+1DLEuuCvZRMQGK3okYSA/ASP7GEqfCDeKmkqzKV2kWrmftNfO+EiIiCnsiyJG4SQ9G7s0OtmCT6wVkphW9wgk7mfUoF5a+Wo3kzvEur3U+7ZfSgLa4HXQG2xE+z7BjmHG8j1qVoVa/3TR1lVBAqOwkodZ9cSPKceK2RxaPkk8gsFbofbuARl5xBqDwkS2caTQu27+DLXT/QJOHRHRw5VtH9v8B7nT+nrijFjktm6hD7aIHuPon6TtEgnbtWltRizEZldh+Fo1Eg==

参考文档配置 head 和 body;

请求代码

package HttpClientTest;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils; /*
* 使用Apache的HttpClient发送GET和POST请求的步骤如下:
* 1. 使用帮助类HttpClients创建CloseableHttpClient对象.
* 2. 基于要发送的HTTP请求类型创建HttpGet或者HttpPost实例.
* 3. 使用addHeader方法添加请求头部,诸如User-Agent, Accept-Encoding等参数.
* 4. 对于POST请求,创建NameValuePair列表,并添加所有的表单参数.然后把它填充进HttpPost实体.
* 5. 通过执行此HttpGet或者HttpPost请求获取CloseableHttpResponse实例
* 6. 从此CloseableHttpResponse实例中获取状态码,错误信息,以及响应页面等等.
* 7. 最后关闭HttpClient资源.
* */ 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("返回消息:" + resData);
// 关闭httpClient资源
httpClient.close();
} catch (Exception e) {
e.printStackTrace();
} }
}

返回信息

{
"out_trade_no":"20181128763521373251698",
"qr_code":"https://qr.alipay.com/bax05640qkuz8quo6tgn2565"
}

以上就是 支付宝 v3 自签名如何实现 的所有内容了,希望对你有所帮助 ✿✿ヽ(°▽°)ノ✿

支付宝 v3 自签名如何实现的更多相关文章

  1. 微信APP支付V3版本签名 && APP下单/订单查询接口Python版实现

    问题背景 最近接入微信支付,微信官方并没有提供Python版的服务端SDK,因而只能根据文档手动实现一版,这里记录一下微信支付的整体流程.踩坑过程与最终具体实现. 微信支付APP下单流程 根据微信官方 ...

  2. Java中的微信支付(1):API V3版本签名详解

    1. 前言 最近在折腾微信支付,证书还是比较烦人的,所以有必要分享一些经验,减少你在开发微信支付时的踩坑.目前微信支付的API已经发展到V3版本,采用了流行的Restful风格. 今天来分享微信支付的 ...

  3. NodeJs支付宝移动支付签名及验签

    非常感谢 :http://www.jianshu.com/p/8513e995ff3a?utm_campaign=hugo&utm_medium=reader_share&utm_co ...

  4. 支付宝App支付签名和验签

    代码: using CMS.Utility.ReturnResult; using OAuthWebAPI.Package; using Common; using System; using Sys ...

  5. php微信支付v3版本签名生成

    前几天需要对接微信支付卡包营销活动需要对接微信新版SDKv3版 签名生成规则,微信的官方文档里面说明的还算可以吧,不过个人觉得不太理想- -.  自己调试的时候调试了半天才找了错误原因. https: ...

  6. 支付宝C# RSA签名 报系统找不到指定的文件问题解决

    做支付宝在线支付模块,安卓和苹果端都没为问题,服务器也能顺利的收到付款异步通知. 在做WEB端支付的时候遇到个奇怪的问题:本地localhost调试支付没问题,代码更新到服务器就出现了未将对象引用设置 ...

  7. 支付宝证书签名 PHP SDK

    PHP 接入支付宝证书方式签名以及验签 支付宝在 2019.10.25 日左右更新了新的 PHP SDK (v4.1.0). 之前的 PHP SDK(v3.4.2) 仅支持公钥方式加签.这次更新之后 ...

  8. 支付宝ios支付请求Java服务端签名报的一个错(ALI40247) 原创

    今天做app的支付宝支付,遇到些问题,以前做支付宝支付签名都是直接在客户端App进行,今天下了最新版本ios的支付宝支付demo,运行demo时底部有红色的显眼字体,告知用户签名必须在服务端进行... ...

  9. 支付宝app支付服务器签名代码(C#)

    1,引入支付宝的sdk(AopSdk) 支付宝接口文档网站可下载,注意下载C#版本: 2,代码写的比较简单 public static string RSASign(string OrderNo,de ...

  10. DELPHI支付宝支付代码

    真实业务场景的考虑 按照支付宝或者微信支付的开发手册的说法,一个标准的客户端接入支付业务模型应该是这样的,我忽略时序图,只用文字描述: 用户登录客户端,选择商品,然后点击客户端支付. 客户端收集商品信 ...

随机推荐

  1. linux下的rpm与yum

    一.源代码形式 1.      绝大多数开源软件都是直接以原码形式发布的 2.      源代码一般会被打成.tar.gz的归档压缩文件 3.      源代码需要编译成为二进制形式之后才能够运行使用 ...

  2. javascript的一些API接口的使用

    1.blob http URL 在编辑器中,有的情况下插入图片,会讲图片转成 blob:http://localhost/*** 的这种形式.这种形式的URL实际数据是存放在浏览器的内存中. 这种情况 ...

  3. vite2+vue3使用tsx报错React is not defined、h is not defined

    vite 为 .jsx 和 .tsx 文件提供开箱即用支持. 如果不是在 react 中使用 jsx,对于报错: React is not defined 需要在 vite.config.js 文件中 ...

  4. (三)Springboot + vue + 达梦数据库构建RBAC权限模型前后端分离脚手架保姆级教程(前端项目)

    XX后台管理系统 1.技术选型与环境要求 1.1 项目技术选型 1.1.1 前端技术 HTML 5 CSS 3 lavaScript Vue Element UI 1.1.2 后端技术 SpringB ...

  5. Redis应用—1.在用户数据里的应用

    大纲 1.社区电商的业务闭环 2.Redis缓存架构的典型生产问题 3.用户数据在读多写少场景下的缓存设计 4.热门用户数据的缓存自动延期机制 5.缓存惊群与穿透问题的解决方案 6.缓存和数据库双写不 ...

  6. 百度地图各种控件:地图平移缩放控件NavigationControl、地图类型控件MapTypeControl

    注:代码复制即可用,标色代码为主要代码 百度地图提供了如下控件: 1.Control:控件的抽象基类,所有控件均继承此类的方法.属性.通过此类您可实现自定义控件. 2.NavigationContro ...

  7. k8s单节点改为高可用和更新证书

    master单节点添加master节点 apiServer添加域名更新证书 更新kubenertes证书有效期 环境 kubernetes v1.22.12 使用kubeadm安装的集群 #添加节点 ...

  8. Web components vs. React

    Web components vs. React - LogRocket Blog Web Components + Compose 是一条更好的路线. 当然,像 molecule 一样用 HTML ...

  9. TensorFlow 中 conv2d 的确切含义

    在读: <TensorFlow:实战Google深度学习框架> 才云科技Caicloud, 郑泽宇, 顾思宇[摘要 书评 试读]图书https://www.amazon.cn/gp/pro ...

  10. Maven 插件 git-commit-id-plugin,打包包含提交信息

    Maven打包发布版本可能会遇到自己的提交不起作用的情况,排查比较困难,可能需要拉下服务器上包,反编译查看是否包含自己的提交记录.如果使用的是GIT作为SCM,可以使用 git-commit-id-p ...