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


    前期准备条件

    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_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(), nullnew 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");
    }
  • 相关阅读:
    html5页面资源预加载(Link prefetch)
    html5页面资源预加载(Link prefetch)
    纯CSS制作的图形效果
    echarts 较全面的参数设置分析
    设置css样式背景色透明 字体颜色的不透明 设置select 箭头样式
    this.refs['hh']获取dom对象,this.refs['hh'].value获取dom对象的值
    浏览器运行的时候 事件打印不出来,提示 此页面出现代码禁用了反向和正向缓存(由于默认事件导致的)
    react 点击事件以及原始event与react封装好的事件点击区别
    react中 props与forEach的用法
    基于webpack的react的环境项目搭建
  • 原文地址:https://www.cnblogs.com/guangxiang/p/12060769.html
Copyright © 2020-2023  润新知