企业微信号红包调用流程 后端
前期准备条件
1.企业号 https://work.weixin.qq.com/
2.已开通支付功能的微信商户号 https://pay.weixin.qq.com/
一、获取支付证书apiclient_cert.p12下载
微信商户平台(pay.weixin.qq.com)-->账户中心-->账户设置-->API安全
(放置到web访问无法下载的地方,防止证书下载泄露)
二、企业台开通微信支付
企业管理后台-->应用管理-->企业支付-->绑定商户平台商户号
三、发放企业红包
官方文档地址:https://work.weixin.qq.com/api/doc/90000/90135/90274
发送红包接口
请求方式: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_namemch_billnomch_idnonce_strre_openidtotal_amountwxappid第一步: 对参数按照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");
}