企業微信號紅包調用流程 後端

前期準備條件

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" );
}
相關文章
相關標籤/搜索