企业微信号红包调用流程 后端

前期准备条件

1.企业号 https://work.weixin.qq.com/html

2.已开通支付功能的微信商户号 https://pay.weixin.qq.com/java

 

 

1、获取支付证书apiclient_cert.p12下载

微信商户平台(pay.weixin.qq.com)-->帐户中心-->帐户设置-->API安全web

(放置到web访问没法下载的地方,防止证书下载泄露)算法

 

2、企业台开通微信支付

企业管理后台-->应用管理-->企业支付-->绑定商户平台商户号c#

 

3、发放企业红包

官方文档地址:https://work.weixin.qq.com/api/doc/90000/90135/90274api

发送红包接口安全

请求方式:POST(HTTPS)
请求地址:https://api.mch.weixin.qq.com/mmpaymkttransfers/sendworkwxredpack
是否须要证书:是
数据格式:xml
部分容易混淆参数说明:
商户号  微信商户平台-->帐户中心-->商户信息-->商户号
公众帐号appid   企业微信后台-->个人企业-->企业信息-->企业ID
用户openid   使用企业用户的userId转为openId  官方文档:http://work.weixin.qq.com/api/doc#11279
 
微信支付签名算法
第一步,设全部发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
特别注意如下重要规则:
参数名ASCII码从小到大排序(字典序);若是参数的值为空不参与签名;参数名区分大小写;验证调用返回或微信主动通知签名时,传送的sign参数不参与签名,将生成的签名与该sign值做校验。微信接口可能增长字段,验证签名时必须支持增长的扩展字段
第二步,在stringA最后拼接上key获得stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将获得的字符串全部字符转换为大写,获得sign值signValue。
附:key为商户平台API密钥里面设置的key,key设置以后不能查看,建议设置后另外保存一份,以避免遗忘。另外,再建议将key顺便保存到 商户平台->产品中心->企业微信收款->API密钥管理 里面,这样后续企业微信收款才能正常使用。
签名字段:
除sign字段外全部字段都参与签名(包括企业微信签名字段workwx_sign一块儿参与签名).
 
 
企业微信签名算法
第一步: 设全部发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
注意:
参数名ASCII码从小到大排序(字典序)若是参数的值为空不参与签名参数名区分大小写传送的sign参数不参与签名,将生成的签名与该sign值做校验
第二步: 在stringA最后拼接上企业微信支付应用secret(参见企业微信管理端支付应用页面的secret),获得stringSignTemp字符串,并对stringSignTemp进行MD5运算,再将获得的字符串全部字符转换为大写,获得sign值signValue。
企业微信签名字段说明:
发红包api固定以下几个字段参与签名:
act_name
mch_billno
mch_id
nonce_str
re_openid
total_amount
wxappid
第一步: 对参数按照key=value的格式,并按照参数名ASCII字典序排序以下
stringA=”act_name=XXX&mch_billno=11111234567890&mch_id=10000098&nonce_str=qFKEgfig76DF9912fewmkp&re_openid=oxTWIuGaIt6gTKsQRLau2M0yL16E&total_amount=100&wxappid=wx12345678
第二步:拼接企业微信支付应用secret(参见企业微信管理端支付应用页面)
stringSignTemp=”stringA&secret=192006250b4c09247ec02edce69f6a2d”
sign=MD5(stringSignTemp).toUpperCase()
 
/** * 发送红包请求 
* @param openId 用户openid
* @param mchBillNo 订单号 
* @param totalAmount 发送金额(单位:分) 
* @param wishing 祝福语 
* @param actName 项目名称(在微信端不显示)
* @param senderName 发送人姓名
* @return
*/
public  Boolean sendWorkWxRedPack(String openId,String mchBillNo, int  totalAmount,String wishing,String actName,String senderName)  throws  Exception 
     Map<String,String> paramMap =  new  TreeMap<>();    
     paramMap.put( "act_name" ,actName); //项目名称    
     paramMap.put( "mch_billno" ,mchBillNo);    
     paramMap.put( "mch_id" ,mchId);    
     paramMap.put( "nonce_str" ,WXPayUtil.generateNonceStr());    
     paramMap.put( "re_openid" ,openId); //openId    
     paramMap.put( "total_amount" ,String.valueOf(totalAmount)); //金额,单位分    
     paramMap.put( "wxappid" ,corpId);    
     String workWxSign = gerCompanySign(paramMap); //生成企业签名   
     paramMap.put( "workwx_sign" ,workWxSign);    
     paramMap.put( "wishing" ,wishing); //红包祝福语    
     paramMap.put( "remark" , "星宏" );    
     paramMap.put( "sender_name" ,senderName);    
     paramMap.put( "sender_header_media_id" , "1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0" );   
     paramMap.put( "scene_id" , "PRODUCT_4" );    
     String paySign = gerPaySign(paramMap); //生成微信支付签名   
     paramMap.put( "sign" ,paySign);    
     String xmlBody = WXPayUtil.mapToXml(paramMap);    
     String request = requestOnce(CP_SEND_WORK_WX_REDPACK,xmlBody, 8 * 1000 , 8 * 1000 , true );   
     Map<String,String> retMap = WXPayUtil.xmlToMap(request);    
     if (retMap.containsKey( "result_code" )&& "SUCCESS" .equals(retMap.get( "result_code" )))
       log.debug( "微信发送参数" +xmlBody);        
       log.debug( "##############发送红包成功:" +request);       
       return  true ;    
     } else {
       log.error( "微信发送参数" +xmlBody);       
       log.error( "###############发送红包失败,返回缘由:" +request);   
       return  false ;   
     }
}
 
/** 
    * 生成签名. 注意,若含有sign_type字段,必须和signType参数保持一致。
    * @param data 待签名数据 
    * @param key API密钥
    * @return 签名
  */
private  static  String generateSignature( final  Map<String, String> data, String key,String type)  throws  Exception {
     Set<String> keySet = data.keySet();    
     String[] keyArray = keySet.toArray( new  String[keySet.size()]);    
     Arrays.sort(keyArray);    
     StringBuffer sb =  new  StringBuffer();    
     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( "&" );    
     }
     if ( "companyPaySecret" .equals(type)){
         sb.append( "secret=" ).append(key);        
         log.debug( "企业拼接结果" +sb.toString());    
     }
     if ( "paySecret" .equals(type)){
         sb.append( "key=" ).append(key);        
         log.debug( "微信支付拼接结果" +sb.toString());   
     }
     String sign = SecureUtil.md5(sb.toString()).toUpperCase();
     log.debug( "生成:" +sign);    
     return  sign;
}

   
/**
* 发送https请求
* @param url 请求地址
* @param data 请求体
* @param connectTimeoutMs 链接超时时间
* @param readTimeoutMs 读取超时时间
* @param useCert 是否使用证书,针对退款、撤销等操做
*/
private  String requestOnce(String url, String data,  int  connectTimeoutMs,  int  readTimeoutMs,  boolean  useCert)  throws  Exception {
     try ( InputStream certStream =  this .getClass().getClassLoader().getResourceAsStream( "apiclient_cert.p12" )){
         BasicHttpClientConnectionManager connManager;        
         if  (useCert) {
             // 证书            
             char [] password = mchId.toCharArray();            
             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  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 );
                             }
 
         HttpClient httpClient = HttpClientBuilder.create().setConnectionManager(connManager).build();
         HttpPost httpPost =  new  HttpPost(url);
         RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(readTimeoutMs).setConnectTimeout(connectTimeoutMs).build();
         httpPost.setConfig(requestConfig);
         StringEntity postEntity =  new  StringEntity(data,  "UTF-8" )
         httpPost.setEntity(postEntity);
         HttpResponse httpResponse = httpClient.execute(httpPost);
         HttpEntity httpEntity = httpResponse.getEntity();
         return  EntityUtils.toString(httpEntity,  "UTF-8" );
}
相关文章
相关标签/搜索