微信支付更换服务器证书

【重要】微信支付计划更换服务器证书,请开发人员验证以免影响交易

尊敬的微信支付商户:

微信支付HTTPS服务器证书的根证书将于2018-08-23日到期,微信支付计划于2018-05-29日更换服务器证书。请通知贵司技术开发人员尽快完成相关验证,确保安装新的根证书,以免影响正常交易。详细流程可参考《微信支付HTTPS服务器证书验证指引》

本文参考:http://baijiahao.baidu.com/s?id=1596185614689507263&wfr=spider&for=pc

=====================================================

一、商户服务器环境说明

服务器:阿里云centos7

开发环境:Java1.8

二、验证步骤

1、微信支付已经将新的服务器证书部署到了沙箱域名(apitest.mch.weixin.qq.com), 如果使用沙箱环境的接口能调用成功,通常表明客户端支持微信支付新的服务器证书。

请求Url:https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey

请求方式:POST

请求格式:XML

请求参数:商户号 mch_id 、随机字符串 nonce_str 、签名 sign

2、参数获取

商户号(mch_id):是微信支付分配的微信商户号,

随机字符串(nonce_str ):是随机字符串,不长于32位,可以通过微信支付api提供的工具类获取:RandomUtil.getRandomStringByLength(32)

签名(sign ):需要通过| 签名生成算法 |获取到。具体办法:

假如传送的参数如下:

mch_id: 10000100nonce_str: ibuaiVcKdpRxkhJA

说明:就需要这两个参数就行了

对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:

stringA="mch_id=10000100&nonce_str=ibuaiVcKdpRxkhJA";

通过MD5拼接API密钥:微信支付api提供了MD5的工具类

String stringSignTemp=stringA+"&key=192006250b4c09247ec02edce69f6a2d"; //注:key为商户平台设置的密钥key String sign = MD5Util.MD5Encode(stringSignTemp).toUpperCase();

这样就获取到了签名sign.

现在需要去验证签名sign是否正确(签名校验工具):

签名验证成功后,通过ssh工具登录到阿里云centos7服务器,通过如下命令进行post提交,验证商户服务器是否支持新的证书

echo '<xml><mch_id>商户号</mch_id><nonce_str>随机数</nonce_str><sign>签名</sign></xml>'|curl -X POST -H 'Content-type:text/xml' -d @- https://apitest.mch.weixin.qq.com/sandboxnew/pay/getsignkey

如果返回如下内容:

<xml>
  <return_code><![CDATA[SUCCESS]]></return_code>
  <return_msg><![CDATA[ok]]></return_msg>
  <sandbox_signkey><![CDATA[5aaf********4517db35451efeb15cd2]]></sandbox_signkey>
</xml>

表示商户服务器支持新的证书。

附相关工具类

public class WXPayConstants {

    public enum SignType {
        MD5, HMACSHA256
    }

    public static final String FAIL     = "FAIL";
    public static final String SUCCESS  = "SUCCESS";
    public static final String HMACSHA256 = "HMAC-SHA256";
    public static final String MD5 = "MD5";

    public static final String FIELD_SIGN = "sign";
    public static final String FIELD_SIGN_TYPE = "sign_type";

    public static final String MICROPAY_URL     = "https://api.mch.weixin.qq.com/pay/micropay";
    public static final String UNIFIEDORDER_URL = "https://api.mch.weixin.qq.com/pay/unifiedorder";
    public static final String ORDERQUERY_URL   = "https://api.mch.weixin.qq.com/pay/orderquery";
    public static final String REVERSE_URL      = "https://api.mch.weixin.qq.com/secapi/pay/reverse";
    public static final String CLOSEORDER_URL   = "https://api.mch.weixin.qq.com/pay/closeorder";
    public static final String REFUND_URL       = "https://api.mch.weixin.qq.com/secapi/pay/refund";
    public static final String REFUNDQUERY_URL  = "https://api.mch.weixin.qq.com/pay/refundquery";
    public static final String DOWNLOADBILL_URL = "https://api.mch.weixin.qq.com/pay/downloadbill";
    public static final String REPORT_URL       = "https://api.mch.weixin.qq.com/payitil/report";
    public static final String SHORTURL_URL     = "https://api.mch.weixin.qq.com/tools/shorturl";
    public static final String AUTHCODETOOPENID_URL = "https://api.mch.weixin.qq.com/tools/authcodetoopenid";

    // sandbox
    public static final String SANDBOX_MICROPAY_URL     = "https://api.mch.weixin.qq.com/sandboxnew/pay/micropay";
    public static final String SANDBOX_UNIFIEDORDER_URL = "https://api.mch.weixin.qq.com/sandboxnew/pay/unifiedorder";
    public static final String SANDBOX_ORDERQUERY_URL   = "https://api.mch.weixin.qq.com/sandboxnew/pay/orderquery";
    public static final String SANDBOX_REVERSE_URL      = "https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/reverse";
    public static final String SANDBOX_CLOSEORDER_URL   = "https://api.mch.weixin.qq.com/sandboxnew/pay/closeorder";
    public static final String SANDBOX_REFUND_URL       = "https://api.mch.weixin.qq.com/sandboxnew/secapi/pay/refund";
    public static final String SANDBOX_REFUNDQUERY_URL  = "https://api.mch.weixin.qq.com/sandboxnew/pay/refundquery";
    public static final String SANDBOX_DOWNLOADBILL_URL = "https://api.mch.weixin.qq.com/sandboxnew/pay/downloadbill";
    public static final String SANDBOX_REPORT_URL       = "https://api.mch.weixin.qq.com/sandboxnew/payitil/report";
    public static final String SANDBOX_SHORTURL_URL     = "https://api.mch.weixin.qq.com/sandboxnew/tools/shorturl";
    public static final String SANDBOX_AUTHCODETOOPENID_URL = "https://api.mch.weixin.qq.com/sandboxnew/tools/authcodetoopenid";

}
public class TestWX {
    
	public static void main(String[] args) {
		testGetSign();
	}

	//测试获取签名
	public static void testGetSign() {
		Map<String, String> reqData = new HashMap<>();
		reqData.put("mch_id", "商户号");
		//获取时间戳
		String nonce_str = generateNonceStr();
		reqData.put("nonce_str", nonce_str);
		String key="商户密钥";
		SignType signType = SignType.MD5;
		String sign = null;
		try {
			sign = generateSignature(reqData, key, signType);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(sign);
		
    }
	
	//测试获取时间戳
	public void testGetNonceStr() {
		String nonce_str = generateNonceStr();
		System.out.println("随机字符串 nonce_str ="+nonce_str);
	}
	
	 /**
     * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
     *
     * @param data 待签名数据
     * @param key API密钥
     * @param signType 签名方式
     * @return 签名
     */
    public static String generateSignature(final Map<String, String> data, String key, SignType signType) throws Exception {
        Set<String> keySet = data.keySet();
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        Arrays.sort(keyArray);
        StringBuilder sb = new StringBuilder();
        for (String k : keyArray) {
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
            if (data.get(k).trim().length() > 0) // 参数值为空,则不参与签名
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        sb.append("key=").append(key);
        if (SignType.MD5.equals(signType)) {
            return MD5(sb.toString()).toUpperCase();
        }
        else if (SignType.HMACSHA256.equals(signType)) {
            return HMACSHA256(sb.toString(), key);
        }
        else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }
    
    /**
     * 生成 MD5
     *
     * @param data 待处理数据
     * @return MD5结果
     */
    public static String MD5(String data) throws Exception {
        java.security.MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }
    
    /**
     * 生成 HMACSHA256
     * @param data 待处理数据
     * @param key 密钥
     * @return 加密结果
     * @throws Exception
     */
    public static String HMACSHA256(String data, String key) throws Exception {
        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        sha256_HMAC.init(secret_key);
        byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }
    
    /**
     * 获取随机字符串 Nonce Str
     *
     * @return String 随机字符串
     */
    public static String generateNonceStr() {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 32);
    }
}

猜你喜欢

转载自my.oschina.net/u/3771868/blog/1798047