前提准備
域名
開發微信網頁授權時需要一個外網可以訪問的域名,因為用戶確認進行微信網頁授權后微信服務器會通過一個回調URL向開發服務器發送一個回調請求。
開發階段可以使用一些內網穿透工具來實現,例如:natapp、花生殼等等。
福利:natapp和花生殼都會免費贈送一些隧道。
注意:natapp提供的免費隧道每次啟動客戶端時產生的域名時隨機的。
填坑:利用花生殼提供的域名進行內網穿透時可能會被微信攔截,所以推薦使用natapp(PS: 請測有效)。
個人訂閱號
由於是進行微信網頁授權,所以需要一個個人微信訂閱號作為開發基礎。
福利:由於微信個人訂閱號沒有提供微信網頁授權功能,但是可以利用微信提供的測試號進行開發。
測試號在哪里:登錄個人訂閱號 -> 開發 -> 開發者工具 -> 公眾平台測試賬號
注意:整個開發過程中都是使用測試號的appID和appsecret
開發環境
JDK: 1.8
MAVEN: 3.x
SpringBoot: 2.x
IDEA: 2017專業版
微信網頁授權官方文檔
文檔路徑
文檔在哪里:登錄微信訂閱號 -> 開發 -> 開發者工具 -> 開發文檔 -> 微信網頁開發 -> 微信網頁授權
回調域名配置
在哪里配置:登錄個人訂閱號 -> 開發 -> 開發者工具 -> 公眾平台測試賬號 -> 網頁服務 -> 網頁賬號 -> 修改 -> 填入授權回調頁面域名即可(推薦使用natapp)
開發步驟
1 第一步:用戶同意授權,獲取code
2 第二步:通過code換取網頁授權access_token
3 第三步:刷新access_token(如果需要)
4 第四步:拉取用戶信息(需scope為 snsapi_userinfo)
5 附:檢驗授權憑證(access_token)是否有效
Java代碼實現
進入微信授權頁面
只需要通過微信瀏覽器訪問到微信授權的頁面即可。
思路
01 用戶通過微信瀏覽器進入一個頁面
02 點擊一個按鈕向開發者后台發送一個GET請求
03 開發這個后台封裝一個URL並重定向到這個URL
代碼片段
/** * 微信網頁授權邏輯入口 * @param map */ @GetMapping(value = "/auth") public void toAuth(ModelMap map, HttpServletRequest request, HttpServletResponse response) throws IOException { log.info("進入微信授權邏輯......"); // 微信網頁授權第一步 - 用戶同意授權,獲取code - start String getCodeUrl = weixinBaseInfoProperties.getAuth().getGetCodeUrl(); String appid = weixinBaseInfoProperties.getAppid(); String appsecret = weixinBaseInfoProperties.getAppsecret(); String redirectUri = weixinBaseInfoProperties.getAuth().getRedirectUri(); String scope = weixinBaseInfoProperties.getAuth().getScope(); getCodeUrl = getCodeUrl.replace("APPID", appid) .replace("REDIRECT_URI", redirectUri) .replace("SCOPE", scope); log.info("封裝好的getCodeUrl為:" + getCodeUrl); response.sendRedirect(getCodeUrl); // 微信網頁授權第一步 - 用戶同意授權,獲取code - end }
獲取CODE和AccessToken、用戶openid、用戶信息
微信用戶通過微信瀏覽器確認授權后,微信服務器會通過之前設定的回調URL向開發者后台發送一個GET請求,這個請求中攜帶了CODE信息。
思路
01 用戶確認授權
02 微信服務器發送回調請求
03 開發服務器接收到回調請求
04 獲取CODE
05 通過CODE在拼裝一個url去請求微信服務器來獲取access_token、openid
06 通過access_token、openid封裝一個url去請求微信服務器來獲取用戶信息
微信網頁授權的使用場景
直接利用微信賬號作為網頁賬號
獲取用戶信息成功后直接跳轉到目標頁面即可
微信賬號和網站賬號進行綁定
思路:
01 獲取用戶信息成功
02 根據用戶openid到數據庫中去查找網頁賬號信息
03 如果查找到信息就說明已經綁定,直接跳轉拿到目標頁面即可
04 如果沒有獲取到就跳轉到登錄綁定頁面
05 用戶輸入賬號和密碼並提交到開發者后台
06 后台需對網站賬號合法性進行校驗
07 校驗通過后進行綁定操作
08 跳轉到目標頁面
代碼片段一
/** * 回調頁面 * @param map * @return */ @GetMapping(value = "/callback") public String callback(ModelMap map, HttpServletRequest request, HttpServletResponse response) { log.info("進入回調處理邏輯......"); String appid = weixinBaseInfoProperties.getAppid(); String appsecret = weixinBaseInfoProperties.getAppsecret(); // 微信網頁授權第二步 - 通過code換取網頁授權access_token - start StringBuffer requestURL = request.getRequestURL(); log.info("進入回調處理邏輯的請求url為:" + requestURL); String code = request.getParameter("code"); log.info("獲取到的用於換取access_token的票據的code值為:" + code); String getAccessTokenUrl = weixinBaseInfoProperties.getAuth().getGetAccessTokenUrl(); getAccessTokenUrl = getAccessTokenUrl.replace("APPID", appid) .replace("SECRET", appsecret) .replace("CODE", code); log.info("封裝好的用於獲取accessToke的url為:" + getAccessTokenUrl); String getAccessTokenResponseStr = httpUtils.doGetStrByRestTemplate(getAccessTokenUrl); log.info("發送獲取access_token請求后的響應為STR:" + getAccessTokenResponseStr); GetAuthAccessTokenResponse getAuthAccessTokenResponse = transformerUtils.String2Object(getAccessTokenResponseStr, GetAuthAccessTokenResponse.class); log.info("發送獲取access_token請求后的響應為:" + getAuthAccessTokenResponse); String access_token = getAuthAccessTokenResponse.getAccess_token(); String open_id = getAuthAccessTokenResponse.getOpenid(); // 微信網頁授權第二步 - 通過code換取網頁授權access_token - end // 微信網頁授權第四步 - 拉取用戶信息(需scope為 snsapi_userinfo) - start String getUserInfoUrl = weixinBaseInfoProperties.getAuth().getGetUserInfoUrl(); getUserInfoUrl = getUserInfoUrl.replace("ACCESS_TOKEN", access_token) .replace("OPENID", open_id); log.info("封裝好的用於獲取userInfo的url為:" + getUserInfoUrl); String getUserInfoResponseStr = httpUtils.doGetStrByRestTemplate(getUserInfoUrl); log.info("發送獲取userInfo請求后的響應為STR:" + getUserInfoResponseStr); GetUserInfoResponse getUserInfoResponse = transformerUtils.String2Object(getUserInfoResponseStr, GetUserInfoResponse.class); log.info("發送獲取userInfo請求后的響應為:" + getUserInfoResponse); // 微信網頁授權第四步 - 拉取用戶信息(需scope為 snsapi_userinfo) - end // 第一種使用:直接使用微信的用戶用戶體系 // map.addAttribute("userinfo", getUserInfoResponse); // return "index2"; // 第二種:微信用戶和網站用戶進行綁定 // 根據openid查詢網站的賬戶信息 UserBindDO userBindDOByOpenid = userBindRepository.findByOpenid(getUserInfoResponse.getOpenid()); if (userBindDOByOpenid != null) { // 已經綁定過的情況 log.info("已經綁定過啦"); map.addAttribute("userinfo", userBindDOByOpenid); return "index3"; } else { // 沒有綁定過的情況 log.info("還未進行綁定操作"); map.addAttribute("openid", getUserInfoResponse.getOpenid()); map.addAttribute("nickname", getUserInfoResponse.getNickname()); return "login"; } }
代碼片段二
@PostMapping(value = "/login") public String login(UserBindDO userBindDO, ModelMap map) { log.info("獲取到的參數信息為:" + userBindDO); // TODO: 對賬戶信息進行格式校驗,如果格式不正確直接返回登錄綁定頁面 // TODO: 驗證賬戶是否存在, 如果不存在直接跳轉到注冊頁面(微信用戶信息同時返回),在注冊邏輯中直接進行綁定 // TODO: 驗證賬戶密碼是否正確,如果部正確直接返回登錄綁定頁面 UserBindDO save = userBindRepository.save(userBindDO); if (save != null) { log.info("bind - 綁定成功"); log.info("綁定后的結果信息為:" + save); map.addAttribute("userinfo", save); return "index3"; } else { log.info("bind - 綁定失敗"); return "login"; } }
源代碼
掃碼獲取