⽀付签名java_Java中的⽀付APIV3版本签名的案例Java中的⽀付API V3版本签名的案例
发布时间:2020-10-29 10:03:01
来源:亿速云
阅读:95
作者:⼩新
这篇⽂章给⼤家分享的是有关Java中的⽀付API V3版本签名的案例的内容。⼩编觉得挺实⽤的,因此分享给⼤家做个参考。⼀起跟随⼩编过来看看吧。
java基础教程栏⽬介绍Java中的⽀付,实现API V3版本签名。
1、 前⾔
最近在折腾⽀付,证书还是⽐较烦⼈的,所以有必要分享⼀些经验,减少你在开发⽀付时的踩坑。⽬前⽀付的API已经发展到V3版本,采⽤了流⾏的Restful风格。
今天来分享⽀付的难点——签名,虽然有很多好⽤的SDK但是如果你想深⼊了解⽀付还是需要了解⼀下的。
2. API证书
为了保证资⾦敏感数据的安全性,确保我们业务中的资⾦往来交易万⽆⼀失。⽬前⽀付第三⽅签
发的权威的CA证书(API证书)中提供的私钥来进⾏签名。通过商户平台你可以设置并获取API证书。
切记在第⼀次设置的时候会提⽰下载,后⾯就不再提供下载了,具体参考说明。
设置后到zip压缩包解压,⾥⾯有很多⽂件,对于JAVA开发来说只需要关注apiclient_cert.p12这个证书⽂件就⾏了,它包含了公私钥,我们需要把它放在服务端并利⽤Java解析.p12⽂件获取公钥私钥。务必保证证书在服务器端的安全,它涉及到资⾦安全。
解析API证书
接下来就是证书的解析了,证书的解析有⽹上很多⽅法,这⾥我使⽤⽐较“正规”的⽅法来解析,利⽤JDK安全包的
java.security.KeyStore来解析。
⽀付API证书使⽤了PKCS12算法,我们通过KeyStore来获取公私钥对的载体KeyPair以及证书序列号serialNumber,我封装了⼯具类:import io.ClassPathResource;import java.security.KeyPair;import
java.security.KeyStore;import java.security.PrivateKey;import java.security.PublicKey;import
X509Certificate;/**
* KeyPairFactory
*
* @author dax
* @since 13:41
**/public class KeyPairFactory { private KeyStore store; private final Object lock = new Object(); /**
* 获取公私钥.
*
* @param keyPath the key path
* @param keyAlias the key alias
* @param keyPass password
* @return the key pair
*/
public KeyPair createPKCS12(String keyPath, String keyAlias, String keyPass) {
ClassPathResource resource = new ClassPathResource(keyPath); char[] pem = CharArray(); try { synchronized (lock) { if (store == null) { synchronized (lock) {
store = Instance("PKCS12");
store.InputStream(), pem);
}
}
}
X509Certificate certificate = (X509Certificate) Certificate(keyAlias);
certificate.checkValidity(); // 证书的序列号 也有⽤
String serialNumber = SerialNumber().toString(16).toUpperCase(); // 证书的 公钥
PublicKey publicKey = PublicKey(); // 证书的私钥
PrivateKey storeKey = (PrivateKey) Key(keyAlias, pem);
return new KeyPair(publicKey, storeKey);
} catch (Exception e) { throw new IllegalStateException("Cannot load keys from store: " + resource, e);
}
}
}复制代码眼熟的可以看出是胖哥Spring Security教程中JWT⽤的公私钥提取⽅法的修改版本,你可以对⽐下不同之处。
这个⽅法中有三个参数,这⾥必须要说明⼀下:keyPath API证书apiclient_cert.p12的classpath路径,⼀般我们会放在resources路径下,当然你可以修改获取证书输⼊流的⽅式。
keyAlias 证书的别名,这个的⽂档是没有的,胖哥通过加载证书时进⾏DEBUG获取到该值固定为Tenpay Certificate 。
keyPass 证书密码,这个默认就是商户号,在其它配置中也需要使⽤就是mchid,就是你⽤超级管理员登录商户平台在个⼈资料中的⼀串数字。
3. V3签名
⽀付V3版本的签名是我们在调⽤具体的⽀付的API时在HTTP请求头中携带特定的编码串供⽀付服务器进⾏验证请求来源,确保请求是真实可信的。
签名格式
签名串的具体格式,⼀共五⾏⼀⾏也不能少,每⼀⾏以换⾏符\n结束。HTTP请求⽅法\n
URL\n
请求时间戳\n
请求随机串\n
请求报⽂主体\n复制代码HTTP请求⽅法 你调⽤的⽀付API所要求的请求⽅法,⽐如APP⽀付为POST。
请求时间戳 服务器系统时间戳,保证服务器时间正确并利⽤System.currentTimeMillis() / 1000获取即可。
请求随机串 个⼯具类⽣成类似593BEC0C930BF1AFEB40B4A08C8FB242的字符串就⾏了。
请求报⽂主体 如果是GET请求直接为空字符"" ;当请求⽅法为POST或PUT时,请使⽤真实发送的JSON报⽂。图⽚上传API,请使⽤meta对应的JSON报⽂。
⽣成签名
然后我们使⽤商户私钥对按照上⾯格式的待签名串进⾏SHA256 with RSA签名,并对签名结果进⾏Base64编码得到签名值。对应的核⼼Java代码为:/**
* V3 SHA256withRSA 签名.
*
* @param method 请求⽅法 GET POST PUT DELETE 等
* @param timestamp 当前时间戳 因为要配置到TOKEN 中所以 签名中的要跟TOKEN 保持⼀致
* @param nonceStr 随机字符串 要和TOKEN中的保持⼀致
* @param body 请求体 GET 为 "" POST 为JSON
* @param keyPair 商户API 证书解析的密钥对 实际使⽤的是其中的私钥
* @return the string
android获取真正的签名*/@SneakyThrowsString sign(String method, String canonicalUrl, long timestamp, String nonceStr, String body, KeyPair keyPair) {
String signatureStr = Stream.of(method, canonicalUrl, String.valueOf(timestamp), nonceStr, body)
.collect(Collectors.joining("\n", "", "\n"));
Signature sign = Instance("SHA256withRSA");
sign.Private());
sign.Bytes(StandardCharsets.UTF_8)); deToString(sign.sign());
}复制代码
4. 使⽤签名
签名⽣成后会同⼀些参数组成⼀个Token放置到对应HTTP请求的Authorization请求头中,格式为:Authorization: WECHATPAY2-SHA256-RSA2048 {Token}复制代码
Token由以下五部分组成:发起请求的商户(包括直连商户、服务商或渠道商)的商户号mchid
商户API证书序列号serial_no,⽤于声明所使⽤的证书
请求随机串nonce_str
时间戳timestamp
签名值signature
Token⽣成的核⼼代码:/**
* ⽣成Token.
*
* @param mchId 商户号
* @param nonceStr 随机字符串
* @param timestamp 时间戳
* @param serialNo 证书序列号
* @param signature 签名
* @return the string
*/String token(String mchId, String nonceStr, long timestamp, String serialNo, String signature) { final String
TOKEN_PATTERN = "mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\""; // ⽣成token return String.format(TOKEN_PATTERN,
nonceStr, timestamp, serialNo, signature);
}复制代码
将⽣成的Token按照上述格式放⼊请求头中即可完成签名的使⽤。
感谢各位的阅读!关于Java中的⽀付API V3版本签名的案例就分享到这⾥了,希望以上内容可以对⼤家有⼀定的帮助,让⼤家可以学到更多知识。如果觉得⽂章不错,可以把它分享出去让更多的⼈看到吧!
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论