java版微信v3签名
java版微信v3签名
第一次研究微信支付功能,采用了微信最新的v3支付版本,此文章编辑的是微信支付签名。
文章有借鉴FrankyTurbo
的文章,此文章仅作为demo
微信官方签名文档
核心代码
对应的替换appid,serial_no等,
证书都放在resources文件夹下
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
/**
* @description:
* @author: zl
* @create: 2020-11-25 16:56
**/
@Slf4j
public class WxPay2 {
String schema = "WECHATPAY2-SHA256-RSA2048 ";
String mchid = "xxxxxxx";
long timestamp = DateUtil.currentSeconds();
String nonceStr = RandomUtil.randomString(16);
String serial_no = "xxxxxxx";
/**
*
* @Description: 获取秘钥
* @Author: zl
* @Date: 2020/11/25 0025
*/
public static PrivateKey getPrivateKey(String filename) throws IOException {
InputStream inputStream = WxPay.class.getClassLoader().getResourceAsStream(filename);
StringBuilder sb = new StringBuilder();
String line;
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
while ((line = br.readLine()) != null) {
sb.append(line);
}
String content = sb.toString();
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(new PKCS8EncodedKeySpec(org.apache.commons.codec.binary.Base64.decodeBase64(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
log.info("异常:" + e);
throw new RuntimeException("无效的密钥格式");
}
}
public String getToken(String method, HttpUrl url, String body) throws IOException {
String message = buildMessage(method, url, timestamp, nonceStr, body);
String signature = sign(message.getBytes("utf-8"));
return "mchid=\"" + mchid + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + serial_no + "\","
+ "signature=\"" + signature + "\"";
}
@SneakyThrows
public String sign(byte[] message) {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(getPrivateKey("apiclient_key.pem"));
sign.update(message);
return Base64.getEncoder().encodeToString(sign.sign());
}
public 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";
}
public void transactions(){
JSONObject jsonObject = new JSONObject();
jsonObject.put("appid","xxxxxxxx");
jsonObject.put("mchid","1604272089");
jsonObject.put("description","测试商品");
jsonObject.put("out_trade_no","202011254529660000001");
jsonObject.put("notify_url","http://127.0.0.1/api/wechatService/weixin/auth");
JSONObject amountJson = new JSONObject();
amountJson.put("total",100);
amountJson.put("currency","CNY");
jsonObject.put("amount",amountJson);
JSONObject payer = new JSONObject();
payer.put("openid","12dadawdlwadlwaojd");
jsonObject.put("payer",payer);
String method = "POST";
HttpUrl httpUrl = HttpUrl.parse("https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi");
try {
HttpRequest request = HttpUtil.createPost(httpUrl.url().toString()).auth(schema + getToken(method,httpUrl,jsonObject.toString())).body(jsonObject.toString());
HttpResponse response = request.execute();
System.out.println(response.body());
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
WxPay2 wxPay2 = new WxPay2();
wxPay2.transactions();
}
}
签名后,调用预支付接口结果:
- 文章仅供参考
- 文章若有不对之处,请提出,避免误导他人