Wechat Public Number Using java Central Control Server-Implementing User Web Page Authorization and Obtaining JS-SDK Privileges

Keywords: JSON Database SDK Mobile

1. Web page authorization refers to the user clicking on the custom menu in the Wechat Public Number to obtain authorized user information in the open page, which can be used to achieve login-free.
The following figure shows the address that needs to be opened by the user, where redirect_uri = points to the address that you really want to jump. For example, you can change the address form from the custom menu jump address to get the code of the address bar on the page.

/**
     * Get information about microcredit users or user openid
     * @param code Parameters with Address Bar after Wechat to Menu Address Redirection
     * @param type 1 Only openid is returned, and 20 user information is returned.
     * @return
     * @throws IOException
     */
    @RequestMapping(value="/getWxUser", method=RequestMethod.POST)
    @ResponseBody
    public Object getWxUser(String code, Integer type) throws IOException{
        log.debug(code);
        log.debug(type);
        if(Assert.isInvalidString(code) || type==null){
            return null;
        }
        //Get access_token and openid
        Map<String, Object> params = new HashMap<String, Object>();
        params.put("appid", SysConfig.getValue(SysConstants.Config.WX_APPID));//Appid of Wechat Public Number
        params.put("secret", SysConfig.getValue(SysConstants.Config.WX_SECRET));//AppSecret, Wechat Public Number
        params.put("code", code);//Parameters with Address Bar after Wechat to Menu Address Redirection
        params.put("grant_type", "authorization_code");
        HttpURLConnection conn = HttpUtil.doGet(SysConstants.Url.WX_OAUTH_ACCESS_TOKEN_URL, params, null);
        JSONObject result = JSONObject.parseObject(HttpUtil.getString(conn));
        log.debug(result);
        if(type==1){
            return result;
        }else if(type==20){
            //Getting User Information
            params = new HashMap<String, Object>();
            //This access_token is dedicated to web authorization, unlike the 2-hour timeout in jssdk, which is up to 2000 times a day, there is no limit on the number of times.
            params.put("access_token", result.get("access_token"));
            params.put("openid", result.get("openid"));
            params.put("lang", "zh_CN");
            conn = HttpUtil.doGet(SysConstants.Url.WX_USERINFO_URL, params, null);
            result = JSONObject.parseObject(HttpUtil.getString(conn));
            log.debug(result);
            return result;
        }else{
            return null;
        }
    }

2. Access to the JS-SDK privileges of Wechat
Getting the rights of Wechat js-sdk can use Wechat to call some functions of the mobile phone, such as taking photos.
The database is used to save access_token and jsapi_ticket, both of which are limited to 2 hours, up to 2,000 times a day.

/**
     * Get the configuration parameters of wx.config
     * @param url
     * @return
     * @throws Exception 
     */
    @RequestMapping(value="/getWxJS", method=RequestMethod.POST)
    @ResponseBody
    public Object configWxJS(String url) throws Exception{
        JSONObject json = new JSONObject();
        String appId = SysConfig.getValue(SysConstants.Config.WX_APPID);

        //1,Search in database jsapi_ticket,Comparing the modification time with the present time whether it is overdue or not(7200Seconds.
        //2,If jsapi_ticket Overdue7200Second), searching in the database access_token,Comparing the modification time with the present time whether it is overdue or not(7200Second), if jsapi_ticket Used directly to encrypt signatures without expiration
        //3,If access_token Overdue, retrieve first access_token,If it is not used out of date access_token Obtain jsapi_ticket
        List<Config> configs = configService.findByProperty("configKey", "jsapi_ticket");//Find jsapi_ticket in database
        Config jsapiticket = Assert.isValidCollection(configs)?configs.get(0):null;
        Long timestamp = System.currentTimeMillis();//current time
        if(jsapiticket==null || Assert.isInvalidString(jsapiticket.getConfigValue()) || (timestamp-jsapiticket.getModifyTime().getTime())/1000l>=jsapiticket.getExpiresIn()){//Determine whether jsapi_ticket expires
            //jsapi_ticket needs to be modified
            configs = configService.findByProperty("configKey", "access_token");//Database lookup access_token
            Config accesstoken = Assert.isValidCollection(configs)?configs.get(0):null;
            if(accesstoken==null || Assert.isInvalidString(accesstoken.getConfigValue()) || (timestamp-accesstoken.getModifyTime().getTime())/1000l>=accesstoken.getExpiresIn()){//Determine whether access_token expires
                //access_token needs to be modified
                Map<String, Object> params = new HashMap<String, Object>();
                params.put("grant_type", "client_credential");
                params.put("appid", appId);
                params.put("secret", SysConfig.getValue(SysConstants.Config.WX_SECRET));
                HttpURLConnection conn = HttpUtil.doGet(SysConstants.Url.WX_JS_ACCESS_TOKEN_URL, params, null);
                JSONObject result = JSONObject.parseObject(HttpUtil.getString(conn));
                log.debug(result.toString());
                if(Assert.isValidString(result.getString("access_token"))){
                    accesstoken = accesstoken==null?new Config():accesstoken;
                    accesstoken.setConfigKey("access_token");
                    accesstoken.setConfigValue(result.getString("access_token"));
                    accesstoken.setExpiresIn(result.getLong("expires_in"));
                    accesstoken.setModifyTime(new Date(timestamp));
                    configService.saveOrUpdate(accesstoken);
                }else{
                     throw new Exception("Obtain access_token Mistakes.");
                }
            }
            //Use access_token to get the modified jsapi_ticket
            Map<String, Object> params = new HashMap<String, Object>();
            params.put("access_token", accesstoken.getConfigValue());
            params.put("type", "jsapi");
            HttpURLConnection conn = HttpUtil.doGet(SysConstants.Url.WX_JSAPI_TICKET, params, null);
            JSONObject result = JSONObject.parseObject(HttpUtil.getString(conn));
            log.debug(result.toString());
            if(Assert.isValidString(result.getString("ticket"))){
                jsapiticket = jsapiticket==null?new Config():jsapiticket;
                jsapiticket.setConfigKey("jsapi_ticket");
                jsapiticket.setConfigValue(result.getString("ticket"));
                jsapiticket.setExpiresIn(result.getLong("expires_in"));
                jsapiticket.setModifyTime(new Date(timestamp));
                configService.saveOrUpdate(jsapiticket);
            }else{
                throw new Exception("Obtain jspapi_ticket Mistakes.");
            }
        }
        //Encrypting signatures using jsapi_ticket
        String nonceStr = UUID.randomUUID().toString().replaceAll("-", "").substring(10, 26);
        String str = "jsapi_ticket="+jsapiticket.getConfigValue()+"&noncestr="+nonceStr+"&timestamp="+timestamp+"&url="+url;
        String signature = DigestUtils.shaHex(str);

        json.put("appId", appId);
        json.put("signature", signature);
        json.put("nonceStr", nonceStr);
        json.put("timestamp", String.valueOf(timestamp));
        log.debug(json.toString());
        return json;
    }

Through this interface, you can get the configuration information needed to call Wechat's js in the page.
wx.config({
debug: true, // turn on debugging mode, the return value of all APIs invoked will come out in alert on the client side. To view the incoming parameters, you can open them on the pc side. The parameter information will be typed out through the log, and printed only on the pc side.
appId:", //Must be filled in, unique identification of public number
Timestamp: // must be filled in to generate a signature timestamp
nonceStr:", //Must be filled in to generate random strings of signatures
Signature:",//Must be filled in, signature, see Appendix 1
jsApiList: []// Must be filled in. List of JS interfaces to be used. See Appendix 2 for a list of all JS interfaces.
});

3. Some important constants

public class SysConstants {
    private SysConstants(){}

    public class Url{
        /**
         * Get the address of authorized access_token
         * Parameter:? Appid =${APPID} & Secret =${SECRET} & code =${CODE} & grant_type = authorization_code
         */
        public static final String WX_OAUTH_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/sns/oauth2/access_token";
        /**
         * Address to obtain user information
         * Parameter:? Access_token=${ACCESS_TOKEN} & openid=${OPENID} & lang= zh_CN
         */
        public static final String WX_USERINFO_URL = "https://api.weixin.qq.com/sns/userinfo";
        /**
         * Get the access_token address of the underlying interface
         * Parameter:? Grant_type = client_credential & appid = APPID & Secret = APPSECRET
         */
        public static final String WX_JS_ACCESS_TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
        /**
         * Get the jsapiticket address
         * ?access_token=ACCESS_TOKEN&type=jsapi
         */
        public static final String WX_JSAPI_TICKET = "https://api.weixin.qq.com/cgi-bin/ticket/getticket";
    }

Posted by GeorgeMoney on Sun, 21 Apr 2019 13:57:33 -0700