zoukankan      html  css  js  c++  java
  • H5游戏接微信小游戏的支付,满满的都是坑!

    h5小游戏接微信的支付,简直是在为难我胖虎,说多了都是泪。
      准备工作:
        准备工作一定要做好,不然很容易出错。首先是session_key这个字段,这个session_key是登录的时候需要用到的,根据code从wx.login获取到。登录成功后直接用客户端保存起来,后面支付的时候要用来签名。

        其次是access_token,这个access_token不是登陆验证用到的那个,我们先看看微信文档里面怎么说。

      是不是很坑,但是支付的时候签名必须要access_token。首先我想到的是存到数据库中,后来我写到监听器中了,但是不知道对不对,代码如下:

        private static String weixin_token = "";
    
        private static Long weixin_token_time = System.currentTimeMillis();
    
        private final static String appId = ConfigHolder.getConfig().getString("gmweb.weixin.AppId");
    
        private final static String secret = ConfigHolder.getConfig().getString("gmweb.weixin.Secret");
    
        public static String getWeixinToken() throws Exception{
            boolean is = true;
            if(weixin_token == null || weixin_token.equals("")){
                is = false;
            }
            if((System.currentTimeMillis()-weixin_token_time)/1000>3600){
                is = false;
            }
            if(!is){
                ObjectMapper mapper = new ObjectMapper();
                String tokenUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid="+appId+"&secret="+secret+"";
                String tokenResult = HttpUtils.sendHttpGet(tokenUrl);
                if(tokenResult!=null&&!tokenResult.equals("")){
                    Map map = mapper.readValue(tokenResult, Map.class);
                    if(map!=null&&map.size()>0){
                        weixin_token = (String)map.get("access_token");
                        weixin_token_time = System.currentTimeMillis();
                    }
                }
            }
            return weixin_token;
        }

        不管哪里用到access_token,都从getWeixinToken()这里面拿,保证唯一性(注意我这里是每隔1个小时拿一次)。好的access_token准备完毕,还剩下米大师签名这个密钥。这个也很坑,其实这个字段就是微信给你的沙箱appkey。

    =========================================================================================================================================================好的准备工作完毕:三个字段 session_key、access_toke、米大师密钥

    =========================================================================================================================================================

    接下来就按照文档进行验证了,小心点一般都没问题(PS:签名的时候参数是按照scii码来进行签名的)

    1、从前端获取参数

    2、米大师签名,mp_sig签名

      注意这里面坑也不少。

      先贴代码:

             token = StartupListener.getWeixinToken();
         String signStr = "amt=" + amt +"&appid=" + appid + "&bill_no=" + bill_no + "&offer_id=" + offer_id + "&openid=" + openid + "&pf=" + pf + "&ts=" + ts + "&zone_id=" + zone_id + "&org_loc=/cgi-bin/midas/sandbox/pay&method=POST&secret=" + miDaShi;; String sign = HmacSHA256.sha256_HMAC(signStr, miDaShi); String mp_signStr = "access_token="+token+"&amt="+amt+"&appid="+appid + "&bill_no=" + bill_no + "&offer_id="+offer_id+"&openid="+openid+"&pf="+pf+ "&sig="+sign+"&ts="+ts+"&zone_id="+zone_id+ "&org_loc=/cgi-bin/midas/sandbox/pay&method=POST&session_key="+sessionKey; String mp_sign = HmacSHA256.sha256_HMAC(mp_signStr, sessionKey);

      

      附上sha256_HMAC代码

    public static String sha256_HMAC(String message, String secret) {
            String hash = "";
            try {
                Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
                SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
                sha256_HMAC.init(secret_key);
                byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
                hash = byteArrayToHexString(bytes);
                System.out.println(hash);
            }
            catch (Exception e) {
                System.out.println("Error HmacSHA256 ===========" + e.getMessage());
            }
            return hash;
        }

    3、发送请求

      好吧,发送请求我也遇到个坑,如果参数不是按照json格式发送,会提示参数缺失。

      

            Map<String,Object> param = new HashMap<String,Object>();
            param.put("openid", openid);
            param.put("appid", appid);
            param.put("offer_id", offer_id);
            param.put("ts", Long.valueOf(ts));
            param.put("zone_id", zone_id);
            param.put("pf", pf);
            param.put("amt", amt);
            param.put("bill_no", bill_no);
            param.put("sig", sign);
            param.put("mp_sig", mp_sign);
            String signResult=HttpUtils.sendHttpPost4(sandUrl+"?"+"access_token="+token, param);  //sandUlr:https://api.weixin.qq.com/cgi-bin/midas/sandbox/pay

      另外附上sendHttpPost4的代码

    public static String sendHttpPost4(String URL, Map<String, Object> map) {
            try {
                URL url = new URL(URL);
                HttpURLConnection connection = (HttpURLConnection) url
                        .openConnection();
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setRequestMethod("POST");
                connection.setUseCaches(false);
                connection.setInstanceFollowRedirects(true);
                connection.setRequestProperty("connection", "Keep-Alive");
                // connection.setRequestProperty("Content-Type",
                // "text/plain; charset=utf-8");
                connection.connect();
                // POST请求
                DataOutputStream out = new DataOutputStream(
                        connection.getOutputStream());
                JSONObject obj = new JSONObject();
                for (Map.Entry<String, Object> entry : map.entrySet()) {
    
                    obj.element(entry.getKey(), entry.getValue());
    
                }
                log.info("pay json is "+obj.toString());
                out.writeBytes(obj.toString());
                out.flush();
                out.close();
                // 读取响应
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        connection.getInputStream()));
                String lines;
                StringBuffer sb = new StringBuffer("");
                while ((lines = reader.readLine()) != null) {
                    lines = new String(lines.getBytes(), "utf-8");
                    sb.append(lines);
                }
                //System.out.println(sb);
                reader.close();
                connection.disconnect();
                return sb.toString();
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }
    
        }

    最后就是解析signResult了,根据返回信息判断是否成功。以上!

  • 相关阅读:
    kotlin,短小精悍
    最近把Vue又看了下
    https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html#webflux-cors
    os模块——获取上层目录
    启动flask服务:flask run -h 0.0.0.0 -p 5000
    22端口和3389端口之我竟然用3389连接linux服务器,关键是我之前用22端口连接过linux!!!
    datetime 模块
    查看公网ip
    字典——删除元素
    docker端口映射
  • 原文地址:https://www.cnblogs.com/yzdtofly/p/9402782.html
Copyright © 2011-2022 走看看