WeChat official payment verification source code analysis

1. Background

With the rapid rise of WeChat, WeChat payment has become an important part of Internet payment methods. As a programmer, on the way to the Internet, it is essential to understand WeChat payment. Here, the author shares the official WeChat payment verification signature processing for the xml data returned by the WeChat callback notification.

2. Source code analysis

1. Official address: https://pay.weixin.qq.com/wiki/doc/api/download/WxPayAPI_JAVA_v3.zip

2. Source code analysis (annotation explanation)

/**
     * 判断签名是否正确
     *
     * @param xmlStr XML格式数据
     * @param key API密钥
     * @return 签名是否正确
     * @throws Exception
     */
 public static boolean isSignatureValid(String xmlStr, String key) throws Exception {
    //将xml格式数据转化为map格式   
    Map<String, String> data = xmlToMap(xmlStr);
        if (!data.containsKey(WXPayConstants.FIELD_SIGN) ) {
            //如果返回xml数据中不包含sign签名标记数据,则直接返回false
            return false;
        }
        //获取微信返回数据中的sign签名数据
        String sign = data.get(WXPayConstants.FIELD_SIGN);
        //将data和key进行签名组装,与返回数据中的sign签名数据对比
        return generateSignature(data, key).equals(sign);
    }
/**
     * 生成签名
     *
     * @param data 待签名数据
     * @param key API密钥
     * @return 签名
     */
    public static String generateSignature(final Map<String, String> data, String key) throws Exception {
        return generateSignature(data, key, SignType.MD5);
    }
 /**
     * 生成签名. 注意,若含有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 {
        //通过keySet获取所有的key集合
        Set<String> keySet = data.keySet();
        //将set转化为数组keyArray
        String[] keyArray = keySet.toArray(new String[keySet.size()]);
        //数组升序排序
        Arrays.sort(keyArray);
        //构建StringBuilder字符串变量
        StringBuilder sb = new StringBuilder();
        //for循环key数组
        for (String k : keyArray) {
            //(重点1)如果数组中包含sign,则继续,不做字符串拼接操作
            if (k.equals(WXPayConstants.FIELD_SIGN)) {
                continue;
            }
             // 参数值为空,则不参与签名
            if (data.get(k).trim().length() > 0)
                //字符串拼接形式:key1=value1&key2=value2
                sb.append(k).append("=").append(data.get(k).trim()).append("&");
        }
        //(重点2)拼接密钥,参数上传的密钥
        sb.append("key=").append(key);
        //如果签名加密方式为MD5,则将字符串所有的英文字符转换为大写字母,再做MD5编码,返回md5加密结果
        if (SignType.MD5.equals(signType)) {
            //(重点3)返回加密结果字符串
            return MD5(sb.toString()).toUpperCase();
        }
        //如果签名加密方式为HMACSHA256,则直接将字符串和key密钥直接生成 HMACSHA256
        else if (SignType.HMACSHA256.equals(signType)) {
            //(重点3)返回加密结果字符串
            return HMACSHA256(sb.toString(), key);
        }
        //如果是其他加密方式,则报异常
        else {
            throw new Exception(String.format("Invalid sign_type: %s", signType));
        }
    }

3. Review

Idea: Analyze the data in the WeChat payment callback notification, filter out the signature sign, replace it with the API payment key, then do string splicing, do MD5 or HMACSHA256 encryption, and return a reverse replacement process of the encrypted result string. Then compare it with the sign signature in the WeChat data. If the same, the signature is passed. Otherwise, do not pass.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326150634&siteId=291194637