受權域名回調
路徑:商戶平臺:帳戶中心 》 帳戶設置 》API安全
一、api 安全配置 (指的是:容許調用接口的白名單配置)
二、證書下載 (本次代碼主要使用的是 p12 證書)
企業付款到零錢,是須要 open_id 參數的,open_id 參數的獲取,參考其餘文章,此處不作記錄
java
import com.alibaba.fastjson.JSONObject; import com.hoohui.project.richeng.model.WeChatEntity; import com.hoohui.project.richeng.util.PathUtil; import com.hoohui.util.http.HttpRequestUtils; import org.apache.commons.lang.StringUtils; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import java.io.*; import java.net.URLEncoder; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; public class WeChatUtils { private byte[] certData; public InputStream getCertStream() { FileInputStream instream = null; try { //此處爲 p12 證書文件路徑 instream = new FileInputStream(new File(PathUtil.getClassResources() + "/weChat/apiclient_cert.p12")); } catch (FileNotFoundException e) { e.printStackTrace(); } return instream; } /** * 隨機串 */ public static String getNonceStr() { UUID uuid = UUID.randomUUID(); return uuid.toString().replace("-", ""); } /** * 方法用途: 對全部傳入參數按照字段名的Unicode碼從小到大排序(字典序),而且生成url參數串<br> * 實現步驟: <br> * * @param paraMap 要排序的Map對象 * @param urlEncode 是否須要URLENCODE * @param keyToLower 是否須要將Key轉換爲全小寫 * true:key轉化成小寫,false:不轉化 * @return */ public static String formatUrlMap(Map<String, String> paraMap, boolean urlEncode, boolean keyToLower) { String buff = ""; Map<String, String> tmpMap = paraMap; try { List<Map.Entry<String, String>> infoIds = new ArrayList<Map.Entry<String, String>>(tmpMap.entrySet()); // 對全部傳入參數按照字段名的 ASCII 碼從小到大排序(字典序) Collections.sort(infoIds, new Comparator<Map.Entry<String, String>>() { @Override public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) { return (o1.getKey()).toString().compareTo(o2.getKey()); } }); // 構造URL 鍵值對的格式 StringBuilder buf = new StringBuilder(); for (Map.Entry<String, String> item : infoIds) { if (StringUtils.isNotBlank(item.getKey())) { String key = item.getKey(); String val = item.getValue(); if (urlEncode) { val = URLEncoder.encode(val, "utf-8"); } if (keyToLower) { buf.append(key.toLowerCase() + "=" + val); } else { buf.append(key + "=" + val); } buf.append("&"); } } buff = buf.toString(); if (buff.isEmpty() == false) { buff = buff.substring(0, buff.length() - 1); } } catch (Exception e) { return null; } return buff; } }
public void toPay() throws Exception { //1. 調用發起支付的方法 String str = mainPay(map, 3000, 3000, true); //2. xml 轉成 map的 方法 Map<String,String> resultMap = XmlUtil.xml2Map(str); //3. 根據 result_code 判斷是否支付成功 if(resultMap.containsKey("result_code") && StringUtils.equals("SUCCESS",resultMap.getOrDefault("result_code",""))){ // TODO: 2019/9/19 表示支付成功 後進行的操做 }else{ // TODO: 2019/9/19表示支付失敗 } } /** * 主要發起支付的方法 */ public static String mainPay(Map<String,String> params, int connectTimeoutMs, int readTimeoutMs,boolean useCert) throws Exception{ Map<String, String> paraMap = new HashMap<>(); //微信 app_id paraMap.put("mch_appid", WeChatConfig.APP_ID); //微信 mch_id paraMap.put("mchid",WeChatConfig.MCH_ID); //隨機字符串 paraMap.put("nonce_str", WeChatUtils.getNonceStr()); //訂單號 能夠按照本身的規則生成,不重複便可 paraMap.put("partner_trade_no","wx"+params.getOrDefault("id","")+ DateUtils.getDate("yyyyMMddHHmmss")); //用戶的 open_id paraMap.put("openid",params.getOrDefault("openid","")); // 校驗用戶姓名選項 NO_CHECK:不校驗真實姓名 FORCE_CHECK:強校驗真實姓名 paraMap.put("check_name","FORCE_CHECK"); // 微信的真實姓名 paraMap.put("re_user_name",params.getOrDefault("re_user_name","")); //金額值,單位爲 分 paraMap.put("amount",params.getOrDefault("amount","")); //企業付款操做說明信息 paraMap.put("desc",params.getOrDefault("desc","")); //跟白名單沒有關係 ,這樣寫就能夠 paraMap.put("spbill_create_ip", InetAddress.getLocalHost().getHostAddress()); //將參數排序,並 拼接成字符串 String url = WeChatUtils.formatUrlMap(paraMap, false, false); //最後加上 商戶 api_key url = url + "&key=" + WeChatConfig.API_KEY; //生成簽名 使用商戶 key //md5 加密,轉大寫 String sign = Md5Utils.md5(url).toUpperCase(); //拼接成xml StringBuffer xml = new StringBuffer(); xml.append("<xml>"); for (Map.Entry<String, String> entry : paraMap.entrySet()) { xml.append("<" + entry.getKey() + ">"); xml.append(entry.getValue()); xml.append("</" + entry.getKey() + ">" + "\n"); } xml.append("<sign>"); xml.append(sign); xml.append("</sign>"); xml.append("</xml>"); logger.info("xml {} ", xml.toString()); BasicHttpClientConnectionManager connManager; if (useCert) { // 證書 char[] password = WeChatConfig.MCH_ID.toCharArray(); //這一步調用獲取證書內容 InputStream certStream = new WeChatUtils().getCertStream(); KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(certStream, password); // 實例化密鑰庫 & 初始化密鑰工廠 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(ks, password); // 建立 SSLContext SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(kmf.getKeyManagers(), null, new SecureRandom()); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( sslContext, new String[]{"TLSv1"}, null, new org.apache.http.conn.ssl.DefaultHostnameVerifier()); connManager = new BasicHttpClientConnectionManager( RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslConnectionSocketFactory) .build(), null, null, null ); } else { connManager = new BasicHttpClientConnectionManager( RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", SSLConnectionSocketFactory.getSocketFactory()) .build(), null, null, null ); } org.apache.http.client.HttpClient httpClient = HttpClientBuilder.create() .setConnectionManager(connManager) .build(); HttpPost httpPost = new HttpPost(WeChatConfig.MACH_PAY_URL); RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build(); httpPost.setConfig(requestConfig); StringEntity postEntity = new StringEntity(xml.toString(), "UTF-8"); httpPost.addHeader("Content-Type", "text/xml"); httpPost.addHeader("User-Agent", "wxpay sdk java v1.0 " + WeChatConfig.MCH_ID); // TODO: 很重要,用來檢測 sdk 的使用狀況,要不要加上商戶信息? httpPost.setEntity(postEntity); HttpResponse httpResponse = httpClient.execute(httpPost); HttpEntity httpEntity = httpResponse.getEntity(); return EntityUtils.toString(httpEntity, "UTF-8"); }