注: 源碼已上傳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; } }
(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); } }
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; } }
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>