java 企业微信向员工付款 证书验证 和 WORKWX_SIGN_ERROR问题解决

1.证书验证

微信文档

https://pay.weixin.qq.com/wiki/doc/api/tools/mch_pay.php?chapter=14_2

企业微信文档

https://work.weixin.qq.com/api/doc#90000/90135/90278

官方文档都说明在企业付款时需要证书进行验证,证书的下载可以看官方给的文档

文档下载之后,我们需要的就是在进行微信支付之前获取正确ssl 连接,让微信后台知道我们是正确的请求

获取ssl连接,向微信后台发起请求:

package cn.com.webi.paycenter.enterprisewechat.util;

import java.io.*;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.net.ssl.SSLContext;

import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * 
 * @version 2.2
 */
@Component
public class HttpUtils {

  private static final String DEFAULT_CHARSET = "UTF-8";
  /**
   * 链接超时时间3秒
   */
  private static final int CONNECT_TIME_OUT = 5000;

  private static final RequestConfig REQUEST_CONFIG = RequestConfig.custom().setConnectTimeout(
      CONNECT_TIME_OUT).build();
  /**
   * 微信支付ssl证书
   */
  private static SSLContext wx_ssl_context = null;


  @Value("${wx.cert.path}")
  public void initCertPath(String certPath) {
    File file = new File(certPath);
    try {
      InputStream ins = new FileInputStream(file);
      KeyStore keystore = KeyStore.getInstance("PKCS12");
      /**
       * 证书密码
       */
      char[] keyPassword = ConfigUtil.getProperty("wx.mchid").toCharArray();
      keystore.load(ins, keyPassword);
      wx_ssl_context = SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }



  /**
   * @description 功能描述: get 请求
   * @param url
   *          请求地址
   * @param params
   *          参数
   * @return 请求失败返回null
   */

  /**
   * @description 功能描述: post 请求
   * @param url
   *          请求地址
   * @param params
   *          参数
   * @return 请求失败返回null
   */

  /**
   * @description 功能描述: post 请求
   * @param url
   *          请求地址
   * @param s
   *          参数xml
   * @return 请求失败返回null
   */



  /**
   * @description 功能描述: post https请求,服务器双向证书验证
   * @param url
   *          请求地址
   * @param s
   *          参数xml
   * @return 请求失败返回null
   */
  public static String posts(String url, String s) {
    CloseableHttpClient httpClient = null;
    HttpPost httpPost = new HttpPost(url);
    String body = null;
    CloseableHttpResponse response = null;
    try {
      httpClient = HttpClients.custom()
          .setDefaultRequestConfig(REQUEST_CONFIG)
          .setSSLSocketFactory(getSSLConnectionSocket())
          .build();
      httpPost.setEntity(new StringEntity(s, DEFAULT_CHARSET));
      response = httpClient.execute(httpPost);
      body = EntityUtils.toString(response.getEntity(), DEFAULT_CHARSET);
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      if (response != null) {
        try {
          response.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }

      if (httpClient != null) {
        try {
          httpClient.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    }
    return body;
  }

  // 获取ssl connection链接
  private static SSLConnectionSocketFactory getSSLConnectionSocket() {
    return new SSLConnectionSocketFactory(wx_ssl_context, new String[] { "TLSv1", "TLSv1.1",
        "TLSv1.2" }, null,
        SSLConnectionSocketFactory.getDefaultHostnameVerifier());
  }
}

证书的密码也就是商户号,正确匹配上就可以,然后在请求微信呢支付时调用

posts(String url, String s)方法,url即微信后台支付路径,s代表请求过去的xml格式的数据,具体可看微信官方后台

 

2.WORKWX_SIGN_ERROR问题解决

这个问题主要是因为没有认真看微信官方的签名算法文档 https://work.weixin.qq.com/api/doc#90000/90135/90281

我想大部分的这个问题都是因为进行签名的时候,给的参数不对

这里有几个关键的地方:① 在获取WORKWX_SIGN签名结果的时候,所需要的签名参数只有 amount,appid , desc,mch_id nonce_str ,openid, partner_trade_no ,ww_msg_type这些参数进行签名,②:需要在最后加上  &secret="企业微信签名固定的secret "进行加签,官方文档也有解释,需要注意

加签数据例子:amount=100&appid=*******&desc=分享的券
                         &mch_id=**********&
                          nonce_str=0rqxxgwx8ojr55j6ph9pyeno7a8z1zx3&
                          openid=os49207d_MBMcU_rDy38Ci55VqHo&
                           partner_trade_no=10000098201411111234567890&
                            ww_msg_type=NORMAL_MSG&secret=*****************

官方解释:

java 企业微信向员工付款 证书验证 和 WORKWX_SIGN_ERROR问题解决