• Java企业微信开发_09_身份验证之移动端网页授权(有完整项目源码)


    注: 源码已上传github: https://github.com/shirayner/WeiXin_QiYe_Demo

     

    一、本节要点

    1.1 授权回调域(可信域名)

    在开始使用网页授权之前,需要先设置一下授权回调域。这里瞬间想到之前做JSSDK的时候,也设置过一个域名。二者本质上都是设置可信域名。

    当用户授权完毕之后,请求将重定向到此域名(或者子域名)下的执行者(jsp页面或者servlet等)。如何设置授权回调域,请见第二节。

    1.2 获取Code

    https://open.weixin.qq.com/connect/oauth2/authorize?appid=CORPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&agentid=AGENTID&state=STATE#wechat_redirect

    可将根据此链接生成一个view菜单按钮,用户点击此按钮时,将跳转到授权页面,授权成功后,页面重定向到指定的REDIRECT_URI页面,同时带上code和state请求参数,即页面将跳转至 redirect_uri?code=CODE&state=STATE页面。

    1.3 移动端网页授权流程

    (1)用户点击1.2中菜单按钮,跳转至授权页面

    (2)用户授权成功,页面重定向到 redirect_uri?code=CODE&state=STATE 页面

    (3)接收code,根据code获取成员信息(UserId,user_ticket)

    (4)拿到UserId后可选择去根据UserId获取成员详细信息, 参见Java企业微信开发_02_通讯录同步 中的 Contacts_UserService类

    (5) 拿到 user_ticket后可选择去使用user_ticket获取成员详情(其中包括用户头像)

    在此我们只关注于打通 企业微信官方文档中 移动端网页授权 相关的接口,这是基础,至于实际工作中企业是如何去具体实现他们自己的授权业务,暂时不在我们讨论的范围内。

     

    二、代码实现

    2.1设置可信域名(授权回调域

    登录企业微信后台—>企业应用—>自建应用中的你的具体应用—>企业微信授权登录—>Web网页

    2.2 生成菜单按钮

    添加一个用于网页授权的菜单按钮,运行MenuTest.testCreateMenu()方法生成按钮。

    在已经成功生成菜单按钮时,有时可能出现菜单没有及时更新的情况,这时可以通过取消关注企业号,再重新关注企业号来解决这个问题。

    (1)MenuService.java

    package com.ray.service;
    
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.google.gson.Gson;
    import com.ray.pojo.menu.Button;
    import com.ray.pojo.menu.CommonButton;
    import com.ray.pojo.menu.ComplexButton;
    import com.ray.pojo.menu.Menu;
    import com.ray.pojo.menu.ViewButton;
    import com.ray.util.WeiXinUtil;
    
    import net.sf.json.JSONObject;
    
    
    public class MenuService {
        private static Logger log = LoggerFactory.getLogger(MenuService.class);  
        // 菜单创建(POST) 限100(次/天)  
        public static String create_menu_url = "https://qyapi.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN&agentid=AGENTID";  
    
        /** 
         * 1.创建菜单 
         *  
         * @param menu 菜单实例 
         * @param accessToken 有效的access_token 
         * @return 0表示成功,其他值表示失败 
         */  
        public void createMenu(String accessToken,Menu menu,int agentId) {  
    
            //1.获取json字符串:将Menu对象转换为json字符串
            Gson gson = new Gson(); 
            String jsonMenu =gson.toJson(menu);      //使用gson.toJson(user)即可将user对象顺序转成json
            System.out.println("jsonMenu:"+jsonMenu);
    
    
            //2.获取请求的url  
            create_menu_url = create_menu_url.replace("ACCESS_TOKEN", accessToken)
                    .replace("AGENTID", String.valueOf(agentId));  
    
            //3.调用接口,发送请求,创建菜单  
            JSONObject jsonObject = WeiXinUtil.httpRequest(create_menu_url, "POST", jsonMenu);  
            System.out.println("jsonObject:"+jsonObject.toString());
    
            //4.错误消息处理
            if (null != jsonObject) {  
                if (0 != jsonObject.getInt("errcode")) {  
                    log.error("创建菜单失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
                }  
            }  
     
        }  
    
        /** 
         * 2.组装菜单数据 
         *  
         * @return 
         */  
        public  Menu getMenu() {  
        /*    ViewButton btn11 = new ViewButton();  
            btn11.setName("添加报销单");  
            btn11.setType("view");  
            btn11.setUrl("http://5nffqn.natappfree.cc/WeiXin_QiYe_Demo/uploadExpenseAccaout.jsp");  
    */
            ViewButton btn11 = new ViewButton();  
            btn11.setName("JSSDK多图上传");  
            btn11.setType("view");  
            btn11.setUrl("http://zvuntx.natappfree.cc/WeiXin_QiYe_Demo/JSSDKUploadPics.jsp");  
    
            ViewButton btn21 = new ViewButton();  
            btn21.setName("JSSDK测试(全)");  
            btn21.setType("view");  
            btn21.setUrl("http://zvuntx.natappfree.cc/WeiXin_QiYe_Demo/jsapiTicktAll.jsp");  
    
            ViewButton btn22 = new ViewButton();  
            btn22.setName("PC端网页授权");  
            btn22.setType("view");  
            btn22.setUrl("https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=ww92f5da92bb24696e&agentid=1000002&redirect_uri=http%3A%2F%2Fzvuntx.natappfree.cc%2FWeiXin_QiYe_Demo%2FPCAuthorization.jsp&state=state");  
    
            ViewButton btn23 = new ViewButton();  
            btn23.setName("移动端网页授权");  
            btn23.setType("view");  
            btn23.setUrl("https://open.weixin.qq.com/connect/oauth2/authorize?appid=ww92f5da92bb24696e&redirect_uri=http%3A%2F%2Fzvuntx.natappfree.cc%2FWeiXin_QiYe_Demo%2FMTAuthorization.jsp&response_type=code&scope=snsapi_privateinfo&agentid=1000002&state=hec#wechat_redirect");  
    
            
            CommonButton btn12 = new CommonButton();  
            btn12.setName("扫一扫");  
            btn12.setType("click");  
            btn12.setKey("12");  
    
            
            
            CommonButton btn13 = new CommonButton();  
            btn13.setName("翻译功能");  
            btn13.setType("click");  
            btn13.setKey("13");  
    
            ViewButton btn14 = new ViewButton();  
            btn14.setName("上传图片");  
            btn14.setType("view");  
            btn14.setUrl("http://5nffqn.natappfree.cc/WeiXin_SanFenBaiXue/uploadimg.jsp");  
    
    
    
            ViewButton btn15 = new ViewButton();  
            btn15.setName("上传图片2");  
            btn15.setType("view");  
            btn15.setUrl("http://5nffqn.natappfree.cc/WeiXin_SanFenBaiXue/index2.jsp");  
    
        
        
    
            
    
            
    
            CommonButton btn24 = new CommonButton();  
            btn24.setName("人脸识别");  
            btn24.setType("click");  
            btn24.setKey("24");  
    
            CommonButton btn25 = new CommonButton();  
            btn25.setName("聊天唠嗑");  
            btn25.setType("click");  
            btn25.setKey("25");  
    
            CommonButton btn31 = new CommonButton();  
            btn31.setName("Q友圈");  
            btn31.setType("click");  
            btn31.setKey("31");  
    
            CommonButton btn33 = new CommonButton();  
            btn33.setName("幽默笑话");  
            btn33.setType("click");  
            btn33.setKey("33");  
    
            CommonButton btn34 = new CommonButton();  
            btn34.setName("用户反馈");  
            btn34.setType("click");  
            btn34.setKey("34");  
    
            CommonButton btn35 = new CommonButton();  
            btn35.setName("关于我们");  
            btn35.setType("click");  
            btn35.setKey("35");  
    
            ViewButton btn32 = new ViewButton();  
            btn32.setName("周边搜索");  
            btn32.setType("view");  
            btn32.setUrl("http://liufeng.gotoip2.com/xiaoqrobot/help.jsp");  
    
            ComplexButton mainBtn1 = new ComplexButton();  
            mainBtn1.setName("正在做功能");  
            mainBtn1.setSub_button(new Button[] { btn11, btn12, btn13, btn14, btn15 });  
    
            ComplexButton mainBtn2 = new ComplexButton();  
            mainBtn2.setName("测试");  
            mainBtn2.setSub_button(new Button[] { btn21, btn22, btn23, btn24, btn25 });  
    
            ComplexButton mainBtn3 = new ComplexButton();  
            mainBtn3.setName("更多");  
            mainBtn3.setSub_button(new Button[] { btn31, btn33, btn34, btn35, btn32 });  
    
            /** 
             * 这是企业号目前的菜单结构,每个一级菜单都有二级菜单项<br> 
             *  
             * 在某个一级菜单下没有二级菜单的情况,menu该如何定义呢?<br> 
             * 比如,第三个一级菜单项不是“更多体验”,而直接是“幽默笑话”,那么menu应该这样定义:<br> 
             * menu.setButton(new Button[] { mainBtn1, mainBtn2, btn33 }); 
             */  
            Menu menu = new Menu();  
            menu.setButton(new Button[] { mainBtn1, mainBtn2, mainBtn3 });  
    
            return menu;  
        }  
    
    }
    View Code

    (2)MenuTest.java

    package com.ray.test;
    
    import org.junit.Test;
    
    import com.ray.pojo.menu.Menu;
    import com.ray.service.MenuService;
    import com.ray.util.WeiXinParamesUtil;
    import com.ray.util.WeiXinUtil;
    
    public class MenuTest {
        
      @Test    
      public void testCreateMenu(){
          //1.组装菜单
          MenuService ms=new MenuService();
          Menu menu=ms.getMenu();
          
          //2.获取access_token:根据企业id和应用密钥获取access_token
          String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
          System.out.println("accessToken:"+accessToken);
          
          //3.创建菜单
          ms.createMenu( accessToken, menu, WeiXinParamesUtil.agentId);
          
         
        
      }
      
      
      
      
    }
    View Code

     2.3 移动端网页授权业务类——MTAuthorizationService.java

    包括两个方法:

    (1)根据code获取成员信息

    (2)使用userTicket获取成员详情

    package com.ray.service;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import com.google.gson.Gson;
    import com.ray.pojo.UserTicket;
    import com.ray.util.WeiXinUtil;
    
    import net.sf.json.JSONObject;
    
    
    /**
     * @desc  : 移动端网页授权Service
     * 
     * @author: shirayner
     * @date  : 2017年9月14日 下午12:18:38
     */
    public class MTAuthorizationService {
        private static Logger log = LoggerFactory.getLogger(MenuService.class);  
    
        public static final String GET_USERINFO_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=ACCESS_TOKEN&code=CODE";  
        
        public static final String GET_USERDETAIL_URL = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserdetail?access_token=ACCESS_TOKEN";  
    
        /** 1.根据code获取成员信息
         * @desc :GET请求、
         * 成员信息包括
         * UserId    成员UserID
         * DeviceId    手机设备号(由企业微信在安装时随机生成,删除重装会改变,升级不受影响)
         * user_ticket    成员票据,最大为512字节。scope为snsapi_userinfo或snsapi_privateinfo,且用户在应用可见范围之内时返回此参数。
         *              后续利用该参数可以获取用户信息或敏感信息。
         * expires_in    user_token的有效时间(秒),随user_ticket一起返回
         *  
         * @param accessToken
         * @param code void
         */
        public JSONObject getUserInfo(String accessToken,String code) {
            //1.获取请求的url  
            String get_userInfo_url=GET_USERINFO_URL.replace("ACCESS_TOKEN", accessToken)
                    .replace("CODE", code);
    
            //2.调用接口,发送请求,获取成员信息
            JSONObject jsonObject = WeiXinUtil.httpRequest(get_userInfo_url, "GET", null);  
            System.out.println("jsonObject:"+jsonObject.toString());
    
            //3.错误消息处理
            if (null != jsonObject) {  
                if (0 != jsonObject.getInt("errcode")) {  
                    log.error("获取成员信息失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
                }  
            }  
            
            return jsonObject;
            
        }
        /** 2.使用userTicket获取成员详情
         * @desc :POST请求
         *  
         * @param accessToken
         * @param userTicket
         * @return JSONObject
         */
        public JSONObject getUserDetail(String accessToken,UserTicket userTicket) {
            //1.获取请求地址  
            String get_userDetail_url=GET_USERDETAIL_URL.replace("ACCESS_TOKEN", accessToken);
    
            //2.准备好请求包体
            Gson gson = new Gson(); 
            String jsonUserTicket =gson.toJson(userTicket);      //使用gson.toJson(user)即可将user对象顺序转成json
            System.out.println("jsonUserTicket:"+jsonUserTicket);
            
            //2.调用接口,发送请求,获取成员信息
            JSONObject jsonObject = WeiXinUtil.httpRequest(get_userDetail_url, "POST", jsonUserTicket);  
            System.out.println("jsonObject:"+jsonObject.toString());
    
            //3.错误消息处理
            if (null != jsonObject) {  
                if (0 != jsonObject.getInt("errcode")) {  
                    log.error("获取成员信息失败 errcode:{} errmsg:{}", jsonObject.getInt("errcode"), jsonObject.getString("errmsg"));  
                }  
            }  
            
            return jsonObject;
            
        }
        
        
    }
    View Code

     2.4前端页面——MTAuthorization.jsp

     授权成功后将跳转到这个页面。在这个页面里调用了MTAuthorizationService中的方法来获取用户信息

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"     %>
        <%@page language="java" import="com.ray.pojo.*"%>
    <%@page language="java" import="com.ray.service.*"%>
    <%@page language="java" import="com.ray.util.*"%>
    <%@page language="java" import="net.sf.json.JSONObject"%>
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>移动端网页授权</title>
    
    <script src="/js/jquery.js"></script>
    <script src="http://rescdn.qqmail.com/node/ww/wwopenmng/js/sso/wwLogin-1.0.0.js"></script>
    </head>
    <body>
    
    <%
             String code= request.getParameter("code");
             String state=request.getParameter("state");
             
             MTAuthorizationService mts=new MTAuthorizationService();
             String accessToken=WeiXinUtil.getAccessToken(WeiXinParamesUtil.corpId, WeiXinParamesUtil.agentSecret).getToken();
             //获取成员信息
             JSONObject userInfo=mts.getUserInfo(accessToken, code);
             
             //获取成员详情
             UserTicket userTicket=new UserTicket();
             userTicket.setUser_ticket(userInfo.getString("user_ticket"));
    
            JSONObject userDetail=mts.getUserDetail(accessToken, userTicket);
            
             
             
    %>
    hello,这里是第三方应用
    code=<%= code%>    <br>
    state=<%= state%>      <br>
    userInfo=<%= userInfo.toString()%>    <br><br>
    userTicket=<%= userInfo.getString("user_ticket")%>   <br><br>
    userDetail=<%= userDetail.toString()%>   <br><br>
    
    </body>
    </html>
    View Code
  • 相关阅读:
    使用高精度计算斐波那契数列 c++
    纪中9日T4 2298. 异或
    洛谷 P1416 攻击火星
    线段树小结
    纪中5日T3 1566. 幸运锁(lucky.pas/c/cpp)
    Title
    Title
    Title
    Title
    Title
  • 原文地址:https://www.cnblogs.com/shirui/p/7520380.html
Copyright © 2020-2023  润新知