微信公眾號03 微信網頁授權
前提準備
域名
開發微信網頁授權時需要一個外網可以訪問的域名,因為使用者確認進行微信網頁授權後微信伺服器會通過一個回撥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) throwsIOException { 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"; } }
原始碼
掃碼獲取