Whole Step of Wechat Silent Authorization

Keywords: JSON SHA1 Attribute Database

First, organize the steps of obtaining authorization.

First, configure the Wechat server.

//Omit import
@RequestMapping("/wechat")
@Controller
public class MobileWechatController {

    private static String token = "wechat";

    @RequestMapping(value = "/testWx")
    public void get(HttpServletRequest request, HttpServletResponse response) throws Exception {

        System.out.println("========WechatController========= ");

        Enumeration pNames = request.getParameterNames();
        while (pNames.hasMoreElements()) {
            String name = (String) pNames.nextElement();
            String value = request.getParameter(name);
            // out.print(name + "=" + value);

            String log = "name =" + name + "     value =" + value;
            System.out.println(log + "aaaa");
        }
        String signature = request.getParameter("signature");/// Wechat Encrypted Signature
        String timestamp = request.getParameter("timestamp");/// Timestamp
        String nonce = request.getParameter("nonce"); /// Random number
        String echostr = request.getParameter("echostr"); // Random string
        PrintWriter out = response.getWriter();
        if (checkSignature(signature, timestamp, nonce)) {
            System.out.println("--------Access Success--------");
            out.print(echostr);
        }
        out.close();
        out = null;
    }
    private static boolean checkSignature(String signature, String timestamp, String nonce) {
        System.out.println("signature:" + signature + "timestamp:" + timestamp + "nonce:" + nonce);
        String[] arr = new String[] { token, timestamp, nonce };
        // Lexicographic ordering of three parameters: token, timestamp and nonce
        Arrays.sort(arr);
        StringBuilder content = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            content.append(arr[i]);
        }
        MessageDigest md = null;
        String tmpStr = null;

        try {
            md = MessageDigest.getInstance("SHA-1");
            // sha1 encryption by splicing three parameter strings into one string
            byte[] digest = md.digest(content.toString().getBytes());
            tmpStr = byteToStr(digest);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }

        content = null;
        // The encrypted string of sha1 can be compared with signature to indicate that the request originated from Wechat.
        System.out.println(tmpStr.equals(signature.toUpperCase()));
        return tmpStr != null ? tmpStr.equals(signature.toUpperCase()) : false;
    }
    /**
     * Converting byte arrays to hexadecimal strings
     *
     * @param byteArray
     * @return
     */
    private static String byteToStr(byte[] byteArray) {
        String strDigest = "";
        for (int i = 0; i < byteArray.length; i++) {
            strDigest += byteToHexStr(byteArray[i]);
        }
        return strDigest;
    }

    /**
     * Converting bytes to hexadecimal strings
     *
     * @param mByte
     * @return
     */
    private static String byteToHexStr(byte mByte) {
        char[] Digit = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
        char[] tempArr = new char[2];
        tempArr[0] = Digit[(mByte >>> 4) & 0X0F];
        tempArr[1] = Digit[mByte & 0X0F];

        String s = new String(tempArr);
        return s;
    }

}

2. Encapsulate the tool class that sends requests to the Wechat server.

  /**
         * Call the other party's interface method
         * @param path Path provided by the other party or third party
         * @param data Data sent to the other party or a third party. In most cases, JSON data is sent to the other party for parsing.
         */
    public static String interfaceUtil(String path, String data) {
            try {
                URL url = new URL(path);
                //Open the connection between url and url
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                PrintWriter out = null;

                /**Setting the parameters of URLConnection and the normal request attribute **** start ***/

                conn.setRequestProperty("accept", "*/*");
                conn.setRequestProperty("connection", "Keep-Alive");
                conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");

                /**Setting the parameters of URLConnection and the normal request attribute **** end ***/

                //Set whether to output to httpUrlConnection, whether to read from httpUrlConnection, and whether to send a post request must set these two
                //The most common Http requests are get and post. Get requests can get static pages, or they can put parameters behind URL strings and pass them to servlet s.
                //The difference between post and get is that the parameters of post are not placed in the URL string, but in the body of the http request.
                conn.setDoOutput(true);
                conn.setDoInput(true);

                conn.setRequestMethod("GET");//GET and POST must be capitalized
                /**GET Method Request*****start*/
                /**
                 * If only GET requests are sent, the connet method is used to establish the actual connection between remote resources.
                 * If you send a POST request, you need to get the output stream corresponding to the URLConnection instance to send the request parameters.
                 * */
                conn.connect();

                /**GET Method Request*****end*/

                /***POST Method Request**** start*/

            /*out = new PrintWriter(conn.getOutputStream());//Get the output stream corresponding to the URLConnection object

            out.print(data);//Send request parameters, that is, data

            out.flush();//Buffer data
            */
                /***POST Method Request**** end*/

                //Get the input stream corresponding to the URLConnection object
                InputStream is = conn.getInputStream();
                //Constructing a character stream cache
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                String str = "";
                String sss = "";
                while ((str = br.readLine()) != null) {
                    str=new String(str.getBytes(),"UTF-8");//Solving the Problem of Chinese Scrambling
                    System.out.println(str);
                    sss = str;
                }
                //Closing flow
                is.close();
                //disconnect, preferably written, when the underlying tcp socket link is idle. If it is being used by other threads, it will not be cut off.
                //Fixed multi-threading, if not disconnected, links will increase until no information can be sent or received. It's normal to write disconnect.
                conn.disconnect();
                System.out.println("Complete End");
                //The database is stored in access token quartz and refreshed in one hour and fifty-nine minutes.

                return sss;
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

All requests and methods of Wechat can be made by this method, for example:

String wechatLogin = WechatUtils.interfaceUtil(
                "https://api.weixin.qq.com/cgi-bin/token?grant_type=" + GRANTTYPE
                        + "&appid=" + APPID
                        + "&secret=" + APPSECRET
                , "");
        // Initiate GET requests for credentials
JSONObject jsonObject = JSON.parseObject(wechatLogin);

Using the above method, the url addresses that will be sent to the WechatLogin server will be assembled according to the requirements, and the returned wechatLogin json string can be received. After a little processing, the returned data can be used.

3. Start the silent authorization of Wechat.

Before we start silent authorization, let's sort out the process.

First, create a menu by code on our public number

 /**
     * create menu
     *
     * @param menu Examples of menus
     * @param accessToken Effective access_token
     * @return 0 Represents success and other values indicate failure
     */
    public static int createMenu(Menu menu, String accessToken) {
        int result = 0;
        // Assemble url to create menu
        String url = MENU_CREATE_URL.replace("ACCESS_TOKEN", accessToken);
        System.out.println("url:"+url);
        // Converting menu objects to json strings
        String jsonMenu = JSONObject.toJSON(menu).toString();
        System.out.println("jsonMenu"+jsonMenu);
        // Call interface to create menu
        JSONObject jsonObject = httpRequest(url, "POST", jsonMenu);
        System.out.println("jsonObject"+jsonObject);
        if (null != jsonObject) {
            if (0 != jsonObject.getInteger("errcode")) {
                result = jsonObject.getInteger("errcode");
                logger.error("Failed to create menu errcode:{} errmsg:{}", jsonObject.getInteger("errcode"), jsonObject.getString("errmsg"));
            }
        }

        return result;
    }

There are two parameters, menu and access Token. accessToken is acquired according to the method in official documents of Wechat. Each access Token takes two hours. However, due to its limited access times, it is recommended to set access Token's acquisition to one time at the server side, when needed. Go to the database and use it. Menu is a button style displayed on the front desk of our Re-public number. It can be assembled by an entity class.

//Modify menu
    private static Menu getMenu(){
        Button btn1 = new Button();
        btn1.setName("Distribution Patrol Inspection");
        btn1.setType("view");
        btn1.setKey("11");
        btn1.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?" +
        "appid=************&" +
        "redirect_uri=http%3A%2F%2Fwww.*******.cn%2F******&" +
        "response_type=code&" +
        "scope=snsapi_base&" +
        "state=123#wechat_redirect");
        System.out.println(btn1.getUrl());
        Menu menu = new Menu();
        menu.setButton(new Button[]{btn1});
        return menu;
    }

Here we focus on the redirect_uri parameter. The parameter path in URI needs to correspond with the development in Wechat Public Platform-interface permission-web page authorization to obtain user's basic information-the domain name in the modification of web page authorization. Otherwise, the menu configured before clicking will appear redirect_url parameter error or redirect_url. These two errors are different from server configuration, as long as attention is paid to correcting the configuration of menu parameters and the domain name of web page authorization.

 

After all these configurations are successful, the user interface should display the complete redirect_url+code=********* in a parameter by clicking the button corresponding to the menu.

Here code is the key to pulling authorization. We use code to assemble the next uri to get the user's unique openid for the public number.

(Attached here is a small method to get the code parameters on the return page)

   public static String getCode(HttpServletRequest request){
        String code = request.getParameter("code");
        System.out.println(code);
        return code;
    }
String code = WechatUtils.getCode(request);
System.out.println("code ----- " + code);
LoginAccessToken loginAccessToken = null;
String accessToken = WechatUtils.interfaceUtil(
          "https://api.weixin.qq.com/sns/oauth2/access_token?" +
          "appid=" + APPID +
          "&secret=" + APPSECRET +
          "&code=" + code +
          "&grant_type=authorization_code"
          ,""
        );
JSONObject jsonObject = JSON.parseObject(accessToken);

Note: The access Token here is different from the global access Token.

So far, the user's openid has been unknowingly acquired by us. This openid can be used to send template messages and other operations. In summary, it is found that the development of Wechat public number is not difficult. It is nothing more than sending http requests + displaying their own pages, and replenishing problems.

Posted by theBond on Thu, 29 Aug 2019 23:27:49 -0700