java微信第三方平台开发(二)

一、获取公众号的的授权


在申请的第三方平台下填写的开发者资料里有:授权测试公众号列表、授权事件接受的URL,首先要在测试列表里添加:公众号的原始ID,然后在URl地址里用java代码处理微信每10分钟推送过来xml啦,然后的步骤是解析xml,获取component_verify_ticket —> 调用接口获取component_access_token —>获取预授权码pre_auth_code(可存在数据库中) — >回复微信success — >引导用户进去授权页 —>获取authorization_code —>换取authorizer_access_token(它和普通公众号的基础token作用一样,也能获取用户的openId和用户信息)

  • 第三方公众号获取微信推送的xml
/**
     * 微信授权事件的接受
     * @return
     */
    @RequestMapping(value="/authorize",method={RequestMethod.GET,RequestMethod.POST})
    public void acceptAuthorizeEvent(
        HttpServletResponse response,HttpServletRequest request){
            try {
                //处理授权事件
                weChatThridService.handleAuthorize(request,response);
                PrintWriter pw = response.getWriter();
                pw.write("success");
                pw.flush();
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }

handleAuthorize方法用来接受处理xml:

  /** 
     * 处理微信授权事件
     * @param request
     * @param response 
     * @throws Exception 
     */
    public void handleAuthorize(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // TODO Auto-generated method stub
        String timestamp=request.getParameter("timestamp");
        String encrypt_type=request.getParameter("encrypt_type");
        String nonce=request.getParameter("nonce");
        String msg_signature=request.getParameter("msg_signature");
        Log.logger.info("timestamp:"+timestamp);
        Log.logger.info("encrypt_type:"+encrypt_type);
        Log.logger.info("nonce:"+nonce);
        Log.logger.info("msg_signature:"+msg_signature);
        //验证通过后

        StringBuilder sb = new StringBuilder();
        BufferedReader in = request.getReader();
        String line;
        while ((line = in.readLine()) != null) {
            sb.append(line);
        }
        String xml = sb.toString();
        Log.logger.info("微信推送的原生:"+xml);
        String encodingAesKey =WeChatContants.encodingAesKey;// 第三方平台组件加密密钥
        String appId=WeChatContants.THRID_APPID;//从xml中解析
        WXBizMsgCrypt pc = new WXBizMsgCrypt(WeChatContants.token, encodingAesKey,appId);
        xml = pc.decryptMsg(msg_signature, timestamp, nonce, xml);
        Log.logger.info("解密后的:"+xml);

上述用到的加密解密工具类可以点击这里下载使用,这里的WeChatContants.token和encodingAesKey就是在开发者资料填写的token和key。

  • 获取component_verify_ticket(第三方验证的票据)
    解析上述解密后的xml文件,获取节点component_verify_ticket内容,后续用来调用微信接口获取第三方通行token.

接上述代码:

     Map<String, String> parseXml = WeChatUtils.parseXml(xml);
        String component_verify_ticket=parseXml.get("ComponentVerifyTicket");
        Log.logger.info(component_verify_ticket);
  • 调用微信接口获取component_access_token
    url:https://api.weixin.qq.com/cgi-bin/component/api_component_token
    method:post
    type:json
    params:
    component_appid(第三方公众号appid,第三方公众号创建好后即可知道)、
    component_appsecret(第三方公众号的appsecret,同上)、
    component_verify_ticket(上步获取到component_verify_ticket)

接上述代码:

      /************调用接口获取component_access_token***************/
        WeChatThridGetTokenVo thridGetToken=new WeChatThridGetTokenVo();
        thridGetToken.setComponent_appid(WeChatContants.THRID_APPID);
        thridGetToken.setComponent_appsecret(WeChatContants.THRID_APPSECRET);
        thridGetToken.setComponent_verify_ticket(component_verify_ticket);
        String result = HttpNetUtils.getInstance().httpByJson(WeChatContants.THRID_COMPONENT_ACCESS_TOKEN, "POST",thridGetToken);
        Log.logger.info(result);

        if(result.contains("component_access_token")){
            WeChatComponentAccessTokenVo componentAccessToken=JSON.parseObject(result,WeChatComponentAccessTokenVo.class);
            component_access_token=componentAccessToken.getComponent_access_token();
        }else{
            Log.logger.info("获取component_access_token失败!");
        }

接上述代码:

 /*****************获取预授权码pre_auth_code*************************/
        Object[]object={component_access_token};
        String preUrl=MessageFormat.format(WeChatContants.THRID_PRE_AUTH_CODE,object);
        WeChatGetPreAuthCodeVo getPreAuthCodeVo=new WeChatGetPreAuthCodeVo();
        getPreAuthCodeVo.setComponent_appid(WeChatContants.THRID_APPID);
        String result1 = HttpNetUtils.getInstance().httpByJson(preUrl,"POST",getPreAuthCodeVo);
        Log.logger.info(result1);
        String preAuthCode="";
        if(result1.contains("pre_auth_code")){
            WeChatPreAuthCodeVo preAuthCodeVo= JSON.parseObject(result1,WeChatPreAuthCodeVo.class);
            preAuthCode=preAuthCodeVo.getPre_auth_code();
            //将预授权码存在数据库中
            Map<String, Object> where = new HashMap<String, Object>();
            where.put("dic_type_id","THRID_WECHAT_PRE_CODE");
            QueryResult<CsDictVo> page = csDictService.findByPage(where);
            if(page.getList()!=null&&page.getList().size()>0){
                CsDictVo csDictVo = page.getList().get(0);
                CsDict csDict=new CsDict();
                BeanCopyPropertyUtils.copyProperties(csDict,csDictVo);
                csDict.setDicCode(preAuthCode);
                csDict.setDicValue(new Date().toString());
                csDictService.update(csDict);
            }
        }else{
            Log.logger.info("获取pre_auth_code失败!");
        }
    }
  • 引导普通公众号进入授权页面进行扫码授权
    从数据库中获取上步存入的预授权码:pre_auth_code,用来访问微信提供的url地址,这是会跳转到微信的一个带二维码的页面,如下图:
    这里写图片描述
    用户扫码授权成功会跳转到你填写的转发地址(和公众号的授权的逻辑步骤是一样的,可以参考我前几篇写的微信开发)并且会带上一个auth_code。
    url地址:https://mp.weixin.qq.com/cgi-bin/componentloginpage?component_appid={0}&pre_auth_code={1}&redirect_uri={2}
    method:get
    params:component_appid、pre_auth_code、redirect_uri(转发的URL地址)
/**
     * 引导用户进入授权页面
     */
    @RequestMapping(value="/goAuthPage",method={RequestMethod.GET,RequestMethod.POST})
    public String goAuthPage(
        HttpServletResponse response,HttpServletRequest request){
        String result="auth";
            try {
                request.getSession();
                //查找预授权码
                String preAuthCode = weChatThridService.getPreAuthCode();
                if(preAuthCode.equals("")){
                    request.setAttribute("errorMsg","预授权码为空!");
                    return "error";
                }
                /**********************跳转到授权页面********************************/
                Object[]object1={WeChatContants.THRID_APPID,preAuthCode,"http://自己的域名.com/a/weixin2/authInfo"};
                String authorizationUrl=MessageFormat.format(WeChatContants.THRID_AUTHORIZATION_CODE,object1);
                Log.logger.info("跳转的URL:"+authorizationUrl);
                response.sendRedirect(authorizationUrl);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        return result;  
    }
  • 获取authorization_code
    request.getParameter(“auth_code”)获取authorization_code,
    getAuthAccessToken方法是获取authorizer_access_token
/**
     * 处理微信授权事件完成跳转URL
     * @return
     */
    @RequestMapping(value="/authInfo",method={RequestMethod.GET,RequestMethod.POST})
    public String successAuthorizeInfo(
        HttpServletResponse response,HttpServletRequest request){
        String result="error";
        try {
            //获取authorization_code  
            String authorization_code=request.getParameter("auth_code");
            Log.logger.info("auth_code:"+authorization_code);
            //换取authorizer_access_token
            String authAccessToken = weChatThridService.getAuthAccessToken(authorization_code);
            if(authAccessToken.equals("configError")){
                request.getSession().setAttribute("errorMsg", "缺少配置,请联系管理员!");
                return "error";
            }else if(authAccessToken.equals("httpError")){
                request.getSession().setAttribute("errorMsg", "微信返回信息失败!");
                return "error";
            }
        }catch (Exception e) {
            // TODO: handle exception
            Log.logger.info(e.getMessage());
        }
        request.setAttribute("errorMsg","授权成功!");
        return result;
    }

注意:authorizer_access_token的有效期为2小时,所以需要存在数据库中。上述接口也会返回:authorizer_refresh_token刷新token,当时间超过2个小时后,开发者需要通过刷新token来更新authorizer_access_token,以此来确保token的长持久性。so,authorizer_refresh_token也需要存在数据库中。

/**
     * 通过authorization_code换取可以调用api的accessToken
     * @param authorization_code
     * @throws Exception 
     */
    public String getAuthAccessToken(String authorization_code) throws Exception {
        // TODO Auto-generated method stub
        String data="";
        Log.logger.info("component_access_token为:"+component_access_token);
        Object[]objects={component_access_token};
        String authAccessToken = MessageFormat.format(WeChatContants.THRID_AUTH_ACCESS_CODE, objects);
        WeChatGetAuthAccessTokenVo getAuthAccessTokenVo =new WeChatGetAuthAccessTokenVo();
        getAuthAccessTokenVo.setAuthorization_code(authorization_code);
        getAuthAccessTokenVo.setComponent_appid(WeChatContants.THRID_APPID);

        String result = HttpNetUtils.getInstance().httpByJson(authAccessToken, "POST", getAuthAccessTokenVo);
        Log.logger.info(result);
        String authorizer_access_token="";
        String authorizer_refresh_token="";
        if(result.contains("authorization_info")){
            WeChatAuthorizationInfoDataVo authInfo= JSON.parseObject(result,WeChatAuthorizationInfoDataVo.class);
            authorizer_access_token=authInfo.getAuthorization_info().getAuthorizer_access_token();
            authorizer_refresh_token=authInfo.getAuthorization_info().getAuthorizer_refresh_token();
        }else{
            Log.logger.info("获取authorizer_access_token失败!");
            data="httpError";
        }
        Log.logger.info(authorizer_access_token);
        //将authorizer_access_token和authorizer_refresh_token存在字典表里
        Map<String, Object> where = new HashMap<String, Object>();
        where.put("dic_type_id","AUTHORIZER_ACCESS_TOKEN");
        QueryResult<CsDictVo> page = csDictService.findByPage(where);
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        if(page.getList()!=null&&page.getList().size()>0){
            CsDictVo csDictVo = page.getList().get(0);
            CsDict csDict=new CsDict();
            BeanCopyPropertyUtils.copyProperties(csDict,csDictVo);
            csDict.setDicCode(authorizer_access_token);
            csDict.setDicValue(sdf.format(new Date()));
            csDictService.update(csDict);
        }else{
            data="configError";
        }
        //将refresh_token存在字典表里
        Map<String, Object> where1 = new HashMap<String, Object>();
        where1.put("dic_type_id","THRID_REFRESH_TOKEN");
        QueryResult<CsDictVo> page1 = csDictService.findByPage(where1);
        if(page1.getList()!=null&&page1.getList().size()>0){
            CsDictVo csDictVo = page.getList().get(0);
            CsDict csDict=new CsDict();
            BeanCopyPropertyUtils.copyProperties(csDict,csDictVo);
            csDict.setDicCode(authorizer_refresh_token);
            csDict.setDicValue(sdf.format(new Date()));
            csDictService.update(csDict);
        }else{
            data="configError";
        }
        return data;
    }
    //调用微信接口重新获取access_token
                Object[]objects={component_access_token};
                String refreshUrl=MessageFormat.format(WeChatContants.THRID_REFRESH_TOKEN, objects);
                WeChatGetRefreshTokenVo refreshTokenVo=new WeChatGetRefreshTokenVo();
                refreshTokenVo.setAuthorizer_appid(wechatConfig.getWxappid());
                refreshTokenVo.setAuthorizer_refresh_token(csDictVo.getDicCode());
                refreshTokenVo.setComponent_appid(WeChatContants.THRID_APPID);
                Log.logger.info(refreshUrl);
                String httpByJson = HttpNetUtils.getInstance().httpByJson(refreshUrl,"POST",refreshTokenVo);
                Log.logger.info(httpByJson);
                if(httpByJson.contains("authorizer_access_token")){
                    WeChatAuthorizerAccessTokenVo authorizerAccessTokenVo = JSON.parseObject(httpByJson, WeChatAuthorizerAccessTokenVo.class);
                    thridToken = authorizerAccessTokenVo.getAuthorizer_access_token();
                    //并将它存在数据字典里面
                    Map<String, Object> where1 = new HashMap<String, Object>();
                    where1.put("dic_type_id","AUTHORIZER_ACCESS_TOKEN");
                    QueryResult<CsDictVo> page1 = csDictService.findByPage(where1);
                    CsDictVo csDictVo2 = page1.getList().get(0);
                    CsDict csDict=new CsDict();
                    BeanCopyPropertyUtils.copyProperties(csDict,csDictVo2);
                    csDict.setDicCode(thridToken);
                    csDict.setDicValue(DateFromtUtils.getDataFormatYMDHMS24(new Date()));
                    csDictService.update(csDict);
                }else{
                    thridToken="httpError";
                }

二、代公众号发起网页授权,获取用户信息


当完成上述步骤后就可以代公众号发起网页授权了,获取用户openID,获取用户信息。

//转发地址
                String redUrl=URLEncoder.encode("http://自己的域名.com/b/weixin2/hongbao", "UTF-8");
                String params=WeChatContants.THRID_WECHAT_OAUTH_PARAMS;
                Object[]array={wechatConfig.getWxappid(),redUrl,"code","snsapi_base",1,WeChatContants.THRID_APPID};
                String formatparams = MessageFormat.format(params, array);
                Log.logger.info(WeChatContants.THRID_WECHAT_OAUTH_URL+"?"+formatparams);
                //将转发地址存在session中,方便code失效时重新连接
                request.getSession().setAttribute("oauthLink",WeChatContants.THRID_WECHAT_OAUTH_URL+"?"+formatparams);
                //微信授权转发
                response.sendRedirect(WeChatContants.THRID_WECHAT_OAUTH_URL+"?"+formatparams);

总结:微信官方文档里至始至终都没提到authorizer_access_token和公众号的token的作用是一样的,并且两者不冲突(即在获取某一个时不会导致另一个失效)。这是微信的一个大坑(吐槽一下…)。

未完待续。。。

猜你喜欢

转载自blog.csdn.net/wei389083222/article/details/53174612