官方文档,https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-sheng-cheng
注意点一:证书私钥获取,商户证书文件下载后,解压,如图,即可读到商户私钥,可以直接提取,也可以通过程序读取文件信息,官方地址:https://wechatpay-api.gitbook.io/wechatpay-api-v3/chang-jian-wen-ti/zheng-shu-xiang-guan#ru-he-cha-kan-zheng-shu-xu-lie-hao
注意点二:证书序列号,本人第一次用,获取方式:登陆商户平台【API安全】->【API证书】->【查看证书】,可查看商户API证书序列号。
java版代码
package com.wsw.sdk.utils;
import okhttp3.HttpUrl;
import sun.misc.BASE64Decoder;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
import java.util.Random;
/**
* @ClassName WxAPIV3SignUtils
* @Description: 微信API-V3签名工具
* @Author wangshiwen
* @Date 2020/3/30
* @Version V1.0
*/
public class WxAPIV3SignUtils {
// Authorization: <schema> <token>
// GET - getToken("GET", httpurl, "")
// POST - getToken("POST", httpurl, json)
public static final String sign_type = "HMAC-SHA256";//签名类型,仅支持HMAC-SHA256。示例值:HMAC-SHA256
private static final String schema = "WECHATPAY2-SHA256-RSA2048";
private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final Random RANDOM = new SecureRandom();
/**
*
* @param method
* @param url
* @param body
* @param mchId 商户号
* @param privateKey 商户证书私钥
* @param serialNo 商户API证书序列号
* @return
* @throws Exception
*/
public static String getToken(String method,HttpUrl url,String body,String mchId,String privateKey,String serialNo) throws Exception{
String nonceStr = generateNonceStr();
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
PrivateKey privateKey1 = getPrivateKey(privateKey);
String signature = sign(message.getBytes("utf-8"),privateKey1);
return schema + " " +"mchid=\"" + mchId + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + serialNo + "\","
+ "signature=\"" + signature + "\"";
}
/**
*
* @param message
* @param privateKey 商户私钥
* @return
*/
private static String sign(byte[] message, PrivateKey privateKey) throws Exception{
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privateKey);
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
private static String buildMessage(String method, HttpUrl url, long timestamp, String nonceStr, String body) {
String canonicalUrl = url.encodedPath();
if (url.encodedQuery() != null) {
canonicalUrl += "?" + url.encodedQuery();
}
return method + "\n"
+ canonicalUrl + "\n"
+ timestamp + "\n"
+ nonceStr + "\n"
+ body + "\n";
}
/**
* String转私钥PrivateKey
* @param key
* @return
* @throws Exception
*/
public static PrivateKey getPrivateKey(String key) throws Exception {
byte[] keyBytes;
keyBytes = (new BASE64Decoder()).decodeBuffer(key);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
return privateKey;
}
/**
* 获取随机字符串 Nonce Str
*
* @return String 随机字符串
*/
public static String generateNonceStr() {
char[] nonceChars = new char[32];
for (int index = 0; index < nonceChars.length; ++index) {
nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
}
return new String(nonceChars);
}
}
调用示例:
Get请求
//请求方式:GET
String url = "https://api.mch.weixin.qq.com/v3/payscore/user-service-state?service_id="+ param.getServiceId() +"&appid="+ param.getAppId() +"&openid=" + param.getOpenId();
HttpUrl httpUrl = HttpUrl.parse(url);
String token = WxAPIV3SignUtils.getToken("GET",httpUrl,"",param.getMchId(),param.getPrivateKey(),param.getSerialNo());
Post请求
//生成签名
String url = "https://api.mch.weixin.qq.com/v3/payscore/serviceorder";
HttpUrl httpUrl = HttpUrl.parse(url);
String token = WxAPIV3SignUtils.getToken("POST",httpUrl,JSON.toJSONString(wxApplyPayScoreIn),payScoreConfig.getMchId(),payScoreConfig.getPrivateKey(),payScoreConfig.getSerialNo());