文件地址
申請入駐文件:pay.weixin.qq.com/wiki/doc/ap…
平臺證照獲取文件:pay.weixin.qq.com/wiki/doc/ap…
1. 微信支付商戶平臺升級API證照,升級後才可成功呼叫本介面。
具體操作看:kf.qq.com/faq/180824B…需要注意的問題,不要著急關閉軟體,等全部完成之後再關閉。
2. 平臺證照獲取(不需要證照)
檢視文件,得知我們需要的引數
- mch_id : 商戶號
- nonce_str:隨機字串,不大於32位
- sign:簽名
- sign_type:簽名型別
- mch_key:簽名引數
為了方便,首先,匯入jar
- 解析xml 需要dom4j
- 由於我們需要從後臺呼叫微信的介面,需要httpclient
<
dependency>
<
groupId>
dom4j<
/groupId>
<
artifactId>
dom4j<
/artifactId>
<
version>
1.6.1<
/version>
<
/dependency>
<
dependency>
<
groupId>
jaxen<
/groupId>
<
artifactId>
jaxen<
/artifactId>
<
version>
1.1.6<
/version>
<
/dependency>
<
dependency>
<
groupId>
org.apache.httpcomponents<
/groupId>
<
artifactId>
httpclient<
/artifactId>
<
version>
4.5.6<
/version>
<
/dependency>
複製程式碼
這邊需要注意的,就是加密,暫只支援HMAC-SHA256,下面提供工具類
Java程式碼
package com.li.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
/** * 簽名加密工具類 * * @author bertonlee */@Slf4jpublic class SignUtil {
/** * 微信證照HMAC-SHA256簽名 * * @param params * @param secret * @return */ public static String wechatCertficatesSignBySHA256(Map<
String, String>
params, String secret) {
// 需要保證排序 SortedMap<
String, String>
sortedMap = new TreeMap<
>
(params);
// 將引數拼接成字串 StringBuilder toSign = new StringBuilder();
for (String key : sortedMap.keySet()) {
String value = params.get(key);
if (StringUtils.isNotEmpty(value) &
&
!"sign".equals(key) &
&
!"key".equals(key)) {
toSign.append(key).append("=").append(value).append("&
");
}
} toSign.append("key=").append(secret);
return sha256_HMAC(toSign.toString(), secret);
} /** * 加密HMAC-SHA256 * * @param message * @param secret * @return */ private static String sha256_HMAC(String message, String secret) {
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
String sign = byteArrayToHexString(bytes);
sign = sign.toUpperCase();
return sign;
} catch (Exception e) {
log.error("sha256_HMAC加密異常", e);
} return null;
} /** * 加密後的位元組轉字串 * * @param b * @return */ private static String byteArrayToHexString(byte[] b) {
StringBuilder hs = new StringBuilder();
String stmp = null;
for (int n = 0;
b != null &
&
n <
b.length;
n++) {
stmp = Integer.toHexString(b[n] &
0XFF);
if (stmp.length() == 1) hs.append('0');
hs.append(stmp);
} return hs.toString().toLowerCase();
}
}複製程式碼
- 其中主要方法wechatCertficatesSignBySHA256
- 將引數排序後進行拼接,規則檢視微信官方的加密規則
- 然後進行加密
- secret 也就是我們的API 金鑰
實現程式碼
package com.li.getcertficates.service.impl;
import com.li.getcertficates.service.CertFicatesService;
import com.li.utils.SignUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
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;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
@Service@Slf4jpublic class CertFicatesServiceImpl implements CertFicatesService {
@Override public String getCertFicates() {
// 初始化一個HttpClient CloseableHttpClient httpClient = HttpClients.createDefault();
// Post請求 HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/risk/getcertficates");
/** * 這邊需要您提供微信分配的商戶號跟API金鑰 */ Map<
String, String>
param = new HashMap<
>
(4);
param.put("mch_id", "微信分配的商戶號");
param.put("nonce_str", UUID.randomUUID().toString().replace("-", ""));
// 暫只支援HMAC-SHA256 加密 param.put("sign_type", "HMAC-SHA256");
// 對你的引數進行加密處理 param.put("sign", SignUtil.wechatCertficatesSignBySHA256(param, "API金鑰(mch_key)"));
httpPost.setEntity(new StringEntity(map2Xml(param), "UTF-8"));
httpPost.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_XML.getMimeType());
try {
HttpResponse httpResponse = httpClient.execute(httpPost);
log.info("獲取平臺證照響應 {
}", httpResponse);
if (httpResponse != null &
&
httpResponse.getStatusLine().getStatusCode() == 200) {
String responseEntity = EntityUtils.toString(httpResponse.getEntity());
Document document = DocumentHelper.parseText(responseEntity);
if ("SUCCESS".equalsIgnoreCase(document.selectSingleNode("//return_code").getStringValue()) &
&
"SUCCESS".equalsIgnoreCase(document.selectSingleNode("//result_code").getStringValue())) {
return document.selectSingleNode("//certificates").getStringValue();
} log.error("請求平臺證照序號響應異常 {
}", document.selectSingleNode("//return_msg").getStringValue());
}
} catch (Exception e) {
log.error("執行httpclient請求平臺證照序號錯誤 {
}", e);
} return null;
} /** * map物件轉xml * * @param map * @return */ private String map2Xml(Map<
String, String>
map) {
StringBuilder result = new StringBuilder();
result.append("<
xml>
");
if (map != null &
&
map.keySet().size() >
0) {
map.forEach((key, value) ->
{
result.append("<
" + key + ">
<
![CDATA[");
result.append(value);
result.append("]]>
<
/" + key + ">
");
});
} result.append("<
/xml>
");
return result.toString();
}
}複製程式碼
- 具體邏輯不難,單純調個介面,響應結果
可以自己寫個main方法,也可以寫個單元測試
最終請求引數
<
xml>
<
sign_type>
HMAC-SHA256<
/sign_type>
<
nonce_str>
qazwsxedcrfvtgbyhnujmiklopasdwefka<
/nonce_str>
<
mch_id>
商戶號<
/mch_id>
<
sign>
FD29B578B31C509B45B7C2779803D9E41B68E6B84AEB1EBDE47DCA00049B649B<
/sign>
<
/xml>
複製程式碼
響應結果
<
xml>
<
return_code>
<
![CDATA[SUCCESS]]>
<
/return_code>
<
return_msg>
<
![CDATA[OK]]>
<
/return_msg>
<
result_code>
<
![CDATA[SUCCESS]]>
<
/result_code>
<
nonce_str>
<
![CDATA[PnDRNZSFzpp2ieUq]]>
<
/nonce_str>
<
sign>
<
![CDATA[AD5919F5FE6D77C308ABEE1A4021CB9839C3F04D7C2FE68FC765011EA3BBEB0F]]>
<
/sign>
<
mch_id>
<
![CDATA[1900006511]]>
<
/mch_id>
<
certificates>
<
![CDATA[{"data":[{"serial_no":"42A5C4F7F70D57D0576BBEDA0E0928D6E5C4F003","effective_time":"2017-08-18 14:52:04","expire_time":"2022-08-17 14:52:04","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"bfcb2bd59c97","associated_data":"certificate","ciphertext":"vQ4N+lLNvtIhaV5Gqao44mbYBSaz3bZ4Md3M4f+OuquEJrp+/v4gA//UZqnQ1G0roYqnSMfcsRFj7ItTCP0tbYregpYqBKd4NSLiF/m1o01JD/9nzd3pBwBUJenUzvE1cuMO+fookaBYr+Z5AfesXUUmvl5qAbD3Yj+5GuMIkTCQcn4W6rls/W2YDo3o3T9sWtl5A/5w+U/Wsb9/UefNow6ND+2MAWRm1GK5tRTkBGVKMt699SM4p0pUns3D4g3slz6zeYIFY3+x+NzrxNq+Ov7I4e/wkp1s3QJd3vctDC4j5btvpCvdEIrBmzzTKzmJ+qhHIRVpXqiMTtOWSpCcTCptUt4v/ZrIlMihESdruDv7Zj4984+4tzBqmQ/Mt1Bwbs8RyKYe2UufmXSMyOeCW06TtkXduZ7M2QSKE4kTlRerEGPatymglepMnjpSMX/CnwaSaHcIBWN2oNjAcuBdMGFlbv05owBlkEZm4sRgZR9EMDIX/N469TUsJ3yXVLuN2k6XaAEM5wpX/Hc15R1o1rhpnLjGZpZoKOVpmcyqw5/0uBQgAAaTXOGgr6L2mrSsp9Au4J0hIX/SjfrjaovXEZTvSM+1oGlJmRVLZ+jxjTD/al7X2xsjTleYYggp4EN4aaC4DTwUNcAAzhHF9R7e+bIfyopa2FF+exXC9kZUYLywg9bwKOJwhkykz7NM669gXLjlyEu6W9gIa8sa3HKSfeLfcpTan7Ev9BjRbowQYmn7RZEyvizKJHJU3ge04OImeJFY4fT8JahzaOT8BQnvP4g2ZT65r4jQwXEbFqOJNH5SdRlTL+3oCqkgMx+1wccaj9ZKqxY9EFDwZgjLZWoySJvIbDQfEayo1pRzlcF9MbuFyGH0vblRLSx3viCc/q6oUkx2OjRw1Hp3sdtFGZMS2OE1+xICymLPglHuMzGkGYwl7ZxbotiXKkqAN46Zd7hNcTwHhxMjQXcoaUoGNEKK1fRZrBv0eUjhES8GbZvzS7+Xm1SR8dKTNMQyEvFesUY143nFt1GK+/bJR+0l2dz0zgpJGAS4yKBkWdsTng0a/jzRbMryRy+fAjWGfvHlVcXXD5b51kx1P3pxcQdMe3K0al+40gLilbegFUVPXhZ04BVgxiWHfeRPnDVwVXFzHG7MAjmPWS0PFzJupZExuy+jxIf5oyHLcYjnl2jwNNcWdzm5AFWYqy5oQI88lcOBx1X+fGuZTKAopk8/2zCa7uu9ILSyVBf801wagINDhxSNemoDoRPE0lvIYE/ax7RQehQ2Q3F2JNmpP6EfP1KZsT6nSWLBf1M5tvX/pAsPbYowNCgrwXLa68L5e03ScplSZrJWP7H3UcGxq9fRLgOYnF7ocRr0iviSRGVmSDqdtpIWwhb+UoAw4347hTQsEHRhYQdR6fTryiANB+H+6SnRJany/cozFV11J03w6h9Lmx95OJGYwF8Cei8S3pNkHpq90o7eUq2PmfS/wwxL3ZyJFPS8OY05zR4ykRnwir4L2X1RyCVoV34AAzVsvr93fVNPHtY3yf+i6sDWb4yGaXaYMM/cOnNs7wrxME44in+YZtPduI+8MZ5EGTbaqjJzrGnrbDnb515OOXg6gk+eV+bJkMXxxoNQGOkLCCI5pN+wrrokXRYhFZbYSkLd/rkg+T3JS23nO1TYOejewvatmQ97i9OFxNrwxOzDL9E87jLj26Wm+VSbm/SNafEh0eU0owwyVskg7evUe7XxcBErXC8M87MuK6AJo/IhhivYlEb/d+wG2r0gV7VesAjYC2n3ZAI1oz78WMMTmj6IqXgDc20uNmGYX0IEB+cxpJwejEfV72ArStqzumUzw3YhvD4L7Ozq0b6Y2gao88MONn9nevnydq5IvsG0bsGutXCFwjhYGxLyqigGIkVkXeq+BbxFpNxbogkB43cM"
}
}]
}]]>
<
/certificates>
<
/xml>
複製程式碼
如上,其他基礎響應外,多了個certificates
- data裡面的serial_no,我們申請入駐需要的引數就是這個
- 其次是encrypt_certificate,主要用來平臺證照解密成金鑰,為申請入駐介面敏感資訊加密處理,後面申請入駐時詳細講解