• 微信支付:小微商户申请入驻第一步:平台证书序列号的获取


    文档地址

    申请入驻文档:https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_2

    平台证书获取文档:https://pay.weixin.qq.com/wiki/doc/api/xiaowei.php?chapter=19_11

    1. 微信支付商户平台升级API证书,升级后才可成功调用本接口。

    具体操作看:http://kf.qq.com/faq/180824BrQnQB180824m6v2yA.html
    需要注意的问题,不要着急关闭软件,等全部完成之后再关闭。

    2. 平台证书获取(不需要证书)

    查看文档,得知我们需要的参数

    1. mch_id : 商户号
    2. nonce_str:随机字符串,不大于32位
    3. sign:签名
    4. sign_type:签名类型
    5. 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
     */
    @Slf4j
    public 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
    @Slf4j
    public 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

    1. data里面的serial_no,我们申请入驻需要的参数就是这个
    2. 其次是encrypt_certificate,主要用来平台证书解密成密钥,为申请入驻接口敏感信息加密处理,后面申请入驻时详细讲解

    第一步完成,欲知后事如何,且听下回分解

    版权声明:本文为不会代码的小白原创文章,转载需添加小白地址 : https://www.ccode.live/bertonlee/list/10?from=art

    源代码:https://github.com/bertonlee/micro-merchant/tree/getcertficates 分支:getcertficates

    欢迎Star

    欢迎关注

    欢迎关注公众号“码上开发”,每天分享最新技术资讯

  • 相关阅读:
    大搜车知乎live中的面试题结题方法记录
    git 学习笔记
    JavaScript 函数节流和函数去抖应用场景辨析
    要不要用gzip优化前端项目
    js和native交互方法浅析
    js设计模式之惰性单例模式
    阻止a标签的默认事件及延伸
    为什么会有OPTIONS请求
    浅析前端渲染与服务端渲染
    exports 和 module.exports 的区别
  • 原文地址:https://www.cnblogs.com/xswz/p/10330022.html
Copyright © 2020-2023  润新知