• 微信支付——沙箱调试环境getsignkey方法秘钥获取及常见问题说明


    官方文档 :https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=23_1

    微信支付PC二维码支付:https://www.cnblogs.com/pxblog/p/10542917.html

    公众号支付:https://www.cnblogs.com/pxblog/p/12815705.html

    在做沙箱测试的时候,微信支付里面的金额固定的,其他金额是无效的。需要按照文档来输入。金额必须是(1.01)

    <xml>
      <return_code><![CDATA[FAIL]]></return_code>
      <return_msg><![CDATA[沙箱支付金额(1)无效,请检查需要验收的case]]></return_msg>
    </xml>

    这里需要用到沙箱秘钥来替换签名中的key,同样验签的时候也是同样用沙箱秘钥获取签名,沙箱秘钥的获取方法

    微信支付仿真测试系统(后简称仿真系统)的简化原理图。仿真系统的API协议与正式API完全相同(API接口文档)。商户开发者只需将正式API的调用URL增加一层sandboxnew路径,即可对接到仿真系统。

    例如,付款码支付URL:https://api.mch.weixin.qq.com/pay/micropay

    变更为:https://api.mch.weixin.qq.com/sandboxnew/pay/micropay。

    仿真系统与生产环境完全独立,包括存储层。商户在仿真系统所做的所有交易(如下单、支付、查询)均为无资金流的假数据,即:用户无需真实扣款,商户也不会有资金入账。代金券同理,沙箱环境中无需商户真实制券与发券,亦不会出现真实扣券情况。验收仿真测试系统的API验签密钥需从API获取:

    支付的接口地址改为:

    https://api2.mch.weixin.qq.com/sandboxnew/pay/unifiedorder
    <xml>
      <return_code><![CDATA[FAIL]]></return_code>
      <return_msg><![CDATA[沙箱验证签名失败,请确认沙箱签名key是否正确(通过getsignkey调用生成)]]></return_msg>
    </xml>

    需要引入

    commons-lang-2.4.jar、jdom-1.1.3.jar

    getSignKeyUtils.java 工具类

    package com.jetcms.weixinpay;
    
    import org.apache.commons.lang.StringUtils;
    import org.jdom.Document;
    import org.jdom.Element;
    import org.jdom.JDOMException;
    import org.jdom.input.SAXBuilder;
    
    import java.io.*;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.net.URLConnection;
    import java.security.MessageDigest;
    import java.util.*;
    
    public class getSignKeyUtils {
    
    
        /**
         *  获取微信支付沙箱API验签密钥 (调用该方法生成)
         * @param nonce_str 随机字符串 生成方法:RandomStringUtils.random(10, N62_CHARS);
         * @param mchId  正式的商户号
         * @param apiKey  正式的密钥
         * @return
         */
        public static String getSignKey(String nonce_str,String mchId,String apiKey) {
            Map<String, String> param = new HashMap<String, String>();
            param.put("mch_id", mchId);//需要真实商户号
            param.put("nonce_str", nonce_str);//随机字符
            String sign = createSign(param, apiKey);//通过SDK生成签名其中API_KEY为商户对应的真实密钥
            param.put("sign", sign);
            String xml = assembParamToXml(param);//将map转换为xml格式
            String url = "https://api.mch.weixin.qq.com/sandboxnew/pay/getsignkey";//沙箱密钥获取api
            Map<String, String> param1 = new HashMap<String, String>();
            String resXml = post(url, xml);
            try {
                if (StringUtils.isNotBlank(resXml)) {
                    param1 = parseXMLToMap(resXml);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            String key = param1.get("sandbox_signkey");
            return key;
        }
    
    
        /**
         * 微信支付签名sign
         * @param param
         * @param key
         * @return
         */
        @SuppressWarnings("unchecked")
        public static String createSign(Map<String, String> param,String key){
            //签名步骤一:按字典排序参数
            List list=new ArrayList(param.keySet());
            Object[] ary =list.toArray();
            Arrays.sort(ary);
            list=Arrays.asList(ary);
            String str="";
            for(int i=0;i<list.size();i++){
                str+=list.get(i)+"="+param.get(list.get(i)+"")+"&";
            }
            //签名步骤二:加上key
            str+="key="+key;
            //步骤三:加密并大写
            str= MD5Encode(str,"utf-8").toUpperCase();
            return str;
        }
    
        /**
         * 将需要传递给微信的参数转成xml格式
         * @param parameters
         * @return
         */
        public static String assembParamToXml(Map<String,String> parameters){
            StringBuffer sb = new StringBuffer();
            sb.append("<xml>");
            Set<String> es = parameters.keySet();
            List<Object> list=new ArrayList<Object>(es);
            Object[] ary =list.toArray();
            Arrays.sort(ary);
            list=Arrays.asList(ary);
            Iterator<Object> it = list.iterator();
            while(it.hasNext()) {
                String key =  (String) it.next();
                String val=(String) parameters.get(key);
                if ("attach".equalsIgnoreCase(key)||"body".equalsIgnoreCase(key)||"sign".equalsIgnoreCase(key)) {
                    sb.append("<"+key+">"+"<![CDATA["+val+"]]></"+key+">");
                }else {
                    sb.append("<"+key+">"+val+"</"+key+">");
                }
            }
            sb.append("</xml>");
            return sb.toString();
        }
    
        public static String post(String urlStr,String xmlInfo) {
            String line1 = "";
            try {
                URL url = new URL(urlStr);
                URLConnection con = url.openConnection();
                con.setDoOutput(true);
                con.setRequestProperty("Cache-Control", "no-cache");
                con.setRequestProperty("Content-Type", "text/xml");
    
                OutputStreamWriter out = new OutputStreamWriter(con
                        .getOutputStream());
                out.write(new String(xmlInfo.getBytes("utf-8")));
                out.flush();
                out.close();
                BufferedReader br = new BufferedReader(new InputStreamReader(con
                        .getInputStream()));
                String line = "";
                for (line = br.readLine(); line != null; line = br.readLine()) {
                    line1+=line;
                }
                return new String(line1.getBytes(),"utf-8");
            } catch (MalformedURLException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    
    
        /**
         * 解析xml,返回第一级元素键值对。如果第一级元素有子节点,则此节点的值是子节点的xml数据。
         * @param strxml
         * @return
         * @throws JDOMException
         * @throws IOException
         */
        public static Map parseXMLToMap(String strxml) throws JDOMException, IOException {
            strxml = strxml.replaceFirst("encoding=".*"", "encoding="UTF-8"");
            if(null == strxml || "".equals(strxml)) {
                return null;
            }
            Map m = new HashMap();
            InputStream in = new ByteArrayInputStream(strxml.getBytes("UTF-8"));
            SAXBuilder builder = new SAXBuilder();
            Document doc = builder.build(in);
            Element root = doc.getRootElement();
            List list = root.getChildren();
            Iterator it = list.iterator();
            while(it.hasNext()) {
                Element e = (Element) it.next();
                String k = e.getName();
                String v = "";
                List children = e.getChildren();
                if(children.isEmpty()) {
                    v = e.getTextNormalize();
                } else {
                    v =getChildrenText(children);
                }
                m.put(k, v);
            }
            //关闭流
            in.close();
            return m;
        }
    
        /**
         * 62个字母和数字,含大小写
         */
        public static final char[] N62_CHARS = {'0', '1', '2', '3', '4', '5', '6',
                '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
                'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
                'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
                'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
                'x', 'y', 'z'};
    
    
        public static String MD5Encode(String origin,String charsetName){
            String resultString=null;
            try{
                resultString=new String(origin);
                MessageDigest md=MessageDigest.getInstance("MD5");
                if(StringUtils.isBlank(charsetName)){
                    resultString=byteArrayToHexString(md.digest(resultString.getBytes()));
                }else{
                    resultString=byteArrayToHexString(md.digest(resultString.getBytes(charsetName)));
                }
            }catch(Exception e){
    
            }
            return resultString;
        }
    
        public static String byteArrayToHexString(byte b[]){
            StringBuffer resultSb=new StringBuffer();
            for(int i=0;i<b.length;i++){
                resultSb.append(byteToHexString(b[i]));
            }
            return resultSb.toString();
        }
    
    
        /**
         * 获取子结点的xml
         * @param children
         * @return String
         */
        public static String getChildrenText(List children) {
            StringBuffer sb = new StringBuffer();
            if(!children.isEmpty()) {
                Iterator it = children.iterator();
                while(it.hasNext()) {
                    Element e = (Element) it.next();
                    String name = e.getName();
                    String value = e.getTextNormalize();
                    List list = e.getChildren();
                    sb.append("<" + name + ">");
                    if(!list.isEmpty()) {
                        sb.append(getChildrenText(list));
                    }
                    sb.append(value);
                    sb.append("</" + name + ">");
                }
            }
            return sb.toString();
        }
    
        public static String byteToHexString(byte b){
            int n=b;
            if(n<0){
                n+=256;
            }
            int d1=n/16;
            int d2=n%16;
            return hexDigits[d1]+hexDigits[d2];
        }
    
        public static final String hexDigits[]={ "0", "1", "2", "3", "4", "5",
                "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
    }

     这个在进入支付操作页面的时候就会进行支付回调,所以不用进行扫码支付操作!!!

     

    -----------------------有任何问题可以在评论区评论,也可以私信我,我看到的话会进行回复,欢迎大家指教------------------------ (蓝奏云官网有些地址失效了,需要把请求地址lanzous改成lanzoux才可以)
  • 相关阅读:
    RFID Hacking②:PM3入门指南
    技术解析:锁屏绕过,三星Galaxy系列手机也能“被”呼出电话
    技术分享:逆向破解华为路由器第一部分
    GSM BTS Hacking: 利用BladeRF和开源BTS 5搭建基站
    js生成随即字符串
    ES6 对象解构
    vue隐藏APP启动时显示的{{}}
    国内常用的三种框架:ionic/mui/framework7对比
    vue for 绑定事件
    html5视频全频播放
  • 原文地址:https://www.cnblogs.com/pxblog/p/13844925.html
Copyright © 2020-2023  润新知