如果 你照着微信文档 做 一直报签名失败 ,但是你敢肯定签名正确,那么 问题出在哪呢, 如上图 红色框所示,这个地方微信文档写错了, 应该 为 boundary=boundary 不加双引号 后面boundary 为任意值 ,比如 boundary=111111 ,具体看下面代码示例。
package com.fykj.web.rest.util;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fykj.tool.document.AuthorizationUtil;
import com.fykj.tool.document.PrivateKeyUtil;
import okhttp3.HttpUrl;
import org.apache.commons.codec.digest.DigestUtils;
import org.junit.Test;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SignatureException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class UploadImageTest2 {
@Test
public void test(){
String privateKeyContent="";
String merchantId="";
String serinalNo="";
String url="https://api.mch.weixin.qq.com/v3/merchant/media/upload";
File file = new File("C:\\Users\\Administrator\\Desktop\\icon.png");
String name = file.getName();
String schema="WECHATPAY2-SHA256-RSA2048";
try {
String boundary="11111111";
System.out.println(boundary);
HttpUrl httpUrl = HttpUrl.get(url);
FileInputStream fileInputStream = new FileInputStream( file);
String sha256Content = DigestUtils.sha256Hex(fileInputStream);
Map<String,Object> map = new HashMap<>();
map.put("filename",name);
map.put("sha256",sha256Content);
ObjectMapper objectMapper = new ObjectMapper();
String json = objectMapper.writeValueAsString(map);
PrivateKey privateKey = PrivateKeyUtil.getPrivateKeyByContent(privateKeyContent);
String encryContent = AuthorizationUtil.getToken("POST", httpUrl, json, privateKey, merchantId, serinalNo);
String authorization=schema+" "+encryContent;
System.out.println(authorization);
URL urlObj = new URL(url);
HttpURLConnection con = (HttpURLConnection)urlObj.openConnection();
//设置请求头
con.setRequestMethod("POST");
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false); //post 方式 不能使用缓存
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
// con.setRequestProperty("Content-type","multipart/form-data");
con.setRequestProperty("Authorization",authorization);
con.setRequestProperty("Content-Type","multipart/form-data;boundary="+boundary);
//请求正文 第一部分
StringBuffer stringBuffer =new StringBuffer();
stringBuffer.append("--"+boundary+"\r\n");
stringBuffer.append("Content-Disposition: form-data; name=\"meta\";"+"\r\n");
stringBuffer.append("Content-Type: application/json"+"\r\n");
stringBuffer.append("\r\n");
stringBuffer.append(json+"\r\n");
stringBuffer.append("--"+boundary+"\r\n");
OutputStream out = new DataOutputStream(con.getOutputStream());
out.write(stringBuffer.toString().getBytes());
out.flush();
//第二部分
StringBuffer stringFileBuffer =new StringBuffer();
stringFileBuffer.append("Content-Disposition: form-data; name=\"file\"; filename=\""+name+"\";"+"\r\n");
stringFileBuffer.append("Content-Type: image/jpg");
stringFileBuffer.append("\r\n");
out.write(stringFileBuffer.toString().getBytes());
out.flush();
// 二进制内容
DataInputStream in = new DataInputStream(fileInputStream);
int length=0;
byte[] bytes = new byte[1024];
while((length=in.read(bytes))!=-1){
out.write(bytes,0,length);
}
in.close();
fileInputStream.close();
String foot ="\r\n"+"--"+boundary+"--"+"\r\n";
out.write(foot.getBytes("utf-8"));
out.flush();
out.close();
String rescontent ="";
Map<String, List<String>> responseHeader = con.getHeaderFields();
for (Map.Entry<String, List<String>> entry : responseHeader.entrySet()) {
System.out.println(entry.getKey()+":" + entry.getValue());
}
int responseCode = con.getResponseCode();
System.out.println(responseCode);
InputStream errorStream = con.getErrorStream();
int BUFFER_SIZE =4096;
ByteArrayOutputStream outStream =new ByteArrayOutputStream();
byte[] data =new byte[BUFFER_SIZE];
int count = -1;
while((count = errorStream.read(data,0,BUFFER_SIZE)) != -1)
outStream.write(data,0, count);
data =null;
byte[] outByte = outStream.toByteArray();
outStream.close();
rescontent =new String(outByte);
System.out.println("图片上传失败:"+rescontent);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (SignatureException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
}
}
}
package com.fykj.tool.document;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Base64;
public class PrivateKeyUtil {
/**
* 获取私钥。
*
* @param filename 私钥文件路径 (required)
* @return 私钥对象
*/
public static PrivateKey getPrivateKey(String filename) throws IOException {
String content = new String(Files.readAllBytes(Paths.get(filename)), "utf-8");
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
/**
* 获取私钥。
*
* @param content 私钥文件路径 (required)
* @return 私钥对象
*/
public static PrivateKey getPrivateKeyByContent(String content) throws IOException {
try {
String privateKey = content.replace("-----BEGIN PRIVATE KEY-----", "")
.replace("-----END PRIVATE KEY-----", "")
.replaceAll("\\s+", "");
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(
new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey)));
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("当前Java环境不支持RSA", e);
} catch (InvalidKeySpecException e) {
throw new RuntimeException("无效的密钥格式");
}
}
}
package com.fykj.tool.document;
import okhttp3.HttpUrl;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.util.Base64;
import java.util.Random;
public class AuthorizationUtil {
public static String getToken(String method, HttpUrl url, String body,PrivateKey yourPrivateKey,String yourMerchantId,String yourCertificateSerialNo) throws UnsupportedEncodingException, NoSuchAlgorithmException, SignatureException, InvalidKeyException {
String nonceStr = "abcdefgh";
long timestamp = System.currentTimeMillis() / 1000;
String message = buildMessage(method, url, timestamp, nonceStr, body);
System.out.println("message===="+message);
String signature = sign(message.getBytes("utf-8"),yourPrivateKey);
return "mchid=\"" + yourMerchantId + "\","
+ "nonce_str=\"" + nonceStr + "\","
+ "timestamp=\"" + timestamp + "\","
+ "serial_no=\"" + yourCertificateSerialNo + "\","
+ "signature=\"" + signature + "\"";
}
private static String sign(byte[] message, PrivateKey yourPrivateKey) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException {
Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(yourPrivateKey);
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";
}
private static String getRandomStringByLength(int length) {
String base = "abcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuffer sb = new StringBuffer();
for (int i = 0; i < length; i++) {
int number = random.nextInt(base.length());
sb.append(base.charAt(number));
}
return sb.toString();
}
}