最近公司給我安排一個微信登陸的功能,需求是這樣的:css
1.登陸受權html
點擊二維碼圖標後,登陸界面切換爲以下樣式(二維碼),微信掃描二維碼並受權,便可成功登陸;html5
若當前帳號未綁定微信帳號,掃描後提示「您的帳號未綁定微信號,請先登陸綁定」;java
點擊「返回」按鈕,界面切換爲帳號密碼登陸;css3
若微信號綁定多個帳號在,則展現所綁定所有帳號的用戶名和企業名,選擇帳號後點擊登陸按鈕成功登陸;spring
2.掃描綁定json
帳號登陸後檢測當前帳號open_id爲空,則展現當前彈窗(001管理員帳號除外);api
用戶微信掃描二維碼後,將當前微信號綁定至對應帳號;安全
若微信號以前綁定其餘帳號,則對應open_id下增長一個帳號;微信
3.我的資料
新增一個'微信號'字段:顯示帳號是否綁定
好,如今整理邏輯,理清思路,畫圖:
聲明一下,PC端的微信掃碼登陸是微信開放平臺,移動端關注是跳轉第三方應用的,用的是公衆平臺,兩個的接口地址拿的openId不同,開放平臺下面若是建立多個應用或者綁定多個公衆號,各公衆號之間用unionId打通。
openId和unionId區別:http://www.25xt.com/html5css3/11968.html
公司或者企業在開發前 登陸微信開放平臺,註冊認證,建立一個應用(應用就是你的項目,產品,不知道就直接讓產品幫你註冊認證,通常須要一個禮拜時間審批+300人民幣,完了拿到AppId和AppSecret)
本身的本地環境要映射到外網,那樣微信才能訪問到本身接口來。推薦使用ngrok,不會的網上有教程,個人是直接讓人幫我配的。
準備工做作好,開始開發:
第一步:根據文檔生成二維碼(開放平臺 --> 資源中心 --> 網站應用 --> 微信登陸功能 --> 網站應用微信登陸開發指南)
我這裏不須要生成整個頁面,而是在一個div裏生成,因此用js生成:
1.在頁面中先引入以下JS文件(支持https):
<script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
2.在須要使用微信登陸的地方實例如下JS對象:
var obj = new WxLogin({ id:"login_container", //div的id appid: "", scope: "", redirect_uri: "", //回調地址 state: "", //參數,可帶可不帶 style: "", //樣式 提供"black"、"white"可選,默認爲黑色文字描述 href: "" //自定義樣式連接,第三方可根據實際需求覆蓋默認樣式。 });
這裏生成的二維碼供用戶掃描,掃描成功,移動端出現受權頁面,需用戶確認。
回調地址裏面的域名要在開放平臺去配:
二維碼就生成好了,能夠看看效果,還沒調樣式:
再來看受權步驟:
第一步,獲取code。
調用接口:https://open.weixin.qq.com/connect/qrconnect?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect;
接口中參數以下:
本身代碼:
1 @Override 2 public Map<String, String> weixinLoginUrl() { 3 String url = "https://open.weixin.qq.com/connect/qrconnect?appid=" + openPlatformAppId + "&redirect_uri=" 4 + URL.encode("'"+ openPlatformRedirect_uri +"'/getWxLoginCode") + "&response_type=code" + "&scope=snsapi_login" 5 + "&state=STATE#wechat_redirect"; 6 Map<String, String> map = new HashMap<String, String>(); 7 map.put("url", url); 8 map.put("getRedirect_uri", openPlatformRedirect_uri); //openPlatformRedirect_uri爲配置文件裏的域名(開放平臺配好的)
9 return map;
10 }
解釋代碼:
openPlatformAppId爲本身的AppId,
openPlatformRedirect_uri爲本身配的域名,(請忽略個人方法命名和參數命名...別學我!)
這裏提一下,登陸的scope=snsapi_login,公衆平臺裏scope有userInfo(用戶有感知)和baseInfo(用戶無感知,靜默受權)
返回給controller,controller從新請求一遍地址,這時候進入的是微信回調地址了,裏面就會有code參數,根據code參數就能夠拿access_token了,controller代碼:
1 @RequestMapping(value = "/wxLoginCheck", method = RequestMethod.GET) 2 @ResponseBody 3 public String wxLoginCheck() { 4 Map<String, String> weixinLoginUrl = alarmWxMessageService.weixinLoginUrl(); 5 String url = weixinLoginUrl.get("url"); 6 return "<script>location.href='" + url + "'</script>"; 7 }
這時候return的回調地址變成了第一步回調地址參數的那個地址("/getWxLoginCode"),域名沒寫了
第二步,經過code獲取access_token
調用接口:https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code;
接口中參數以下:
本身代碼:
controller:
1 @RequestMapping(value = "/getWxLoginCode", method = RequestMethod.GET) 2 public String getWxLoginCode(String code) { 3 WeixinOauth2Token wxot=alarmWxMessageService.wxLogingetCode(code); 4 String openId = wxot.getOpenId(); 5 String accessToken = wxot.getAccessToken(); 6 }
解釋代碼:
code直接能拿到了,WeixinOauth2Token 爲實體類,封裝openId和access_token之類字段
serviceImpl:
1 @Override 2 public WeixinOauth2Token wxLogingetCode(String code) { 3 WeixinOauth2Token wat = null; 4 String getTokenUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=" + openPlatformAppId 5 + "&secret=" + openPlatformAppSecret 6 + "&code=" + code 7 + "&grant_type=authorization_code"; 8 // 獲取網頁受權憑證 9 JSONObject jsonObject = JSONObject.fromObject(HttpUtil.Get(getTokenUrl)); 10 if (jsonObject != null) { 11 try { 12 wat = new WeixinOauth2Token(); 13 wat.setAccessToken(jsonObject.getString("access_token")); 14 wat.setOpenId(jsonObject.getString("openid"));15 } catch (Exception e) { 16 wat = null; 17 int errorCode = jsonObject.getInt("errorCode"); 18 String errorMsg = jsonObject.getString("errorMsg"); 19 log.error("獲取網頁受權失敗errorCode=" + errorCode + ",errorMsg=" + errorMsg); 20 } 21 } 22 return wat; 23 }
解釋代碼:
openPlatformAppId爲本身的AppId,
openPlatformAppSecret爲本身的密碼,
code爲以前獲取到的code,
json那一段是從新發送一個get請求,方法在HttpUtil裏封裝的,下面貼出。
1 /** 2 * 向指定URL發送GET方法的請求 3 * 4 * @param url 發送請求的URL 5 * @param param 請求參數,請求參數應該是 name1=value1&name2=value2 的形式。 6 * @return URL 所表明遠程資源的響應結果 7 */ 8 public static String Get(String url) { 9 int connectionTimeOut=HTTP_CONNECTION_TIMEOUT, readTimeOut =HTTP_READ_TIMEOUT; 10 String result = ""; 11 BufferedReader in = null; 12 String urlNameString = url; 13 try { 14 logger.info("請求url+參數:" + urlNameString); 15 URL realUrl = new URL(urlNameString); 16 // 打開和URL之間的鏈接 17 URLConnection connection = realUrl.openConnection(); 18 // 設置通用的請求屬性 19 connection.setRequestProperty("accept", "*/*"); 20 connection.setRequestProperty("connection", "Keep-Alive"); 21 connection.setConnectTimeout(connectionTimeOut); 22 connection.setReadTimeout(readTimeOut); 23 // 創建實際的鏈接 24 connection.connect(); 25 // 獲取全部響應頭字段 26 // 定義 BufferedReader輸入流來讀取URL的響應 27 in = new BufferedReader(new InputStreamReader(connection.getInputStream())); 28 String line; 29 while ((line = in.readLine()) != null) { 30 result += line; 31 } 32 } catch (Exception e) { 33 logger.error("發送GET請求出現異常!url: " + urlNameString + ", " + e); 34 } 35 // 使用finally塊來關閉輸入流 36 finally { 37 try { 38 if (in != null) { 39 in.close(); 40 } 41 } catch (Exception e2) { 42 logger.error("close exception", e2); 43 } 44 } 45 return result; 46 }
到這裏,已經受權完了,能拿到用戶的openId,用這個去完成公司相關業務。文檔上面的刷新access_token沒有作,本身能夠去了解下
後來作完了,推送消息那邊要拿我這個openId,才發現,登陸是開放平臺的,推送消息是公衆平臺的,平臺都不同,openId確定不同,因此又從新開發一遍登陸,什麼東西都是本身實現。。。。。。
注意:unionId,統一管理多個公衆號或者多個應用而產生的一個機制,像此次開發的,開放平臺和公衆平臺不能用這個
我的總結一下,開發一個東西以前,思路必定要理清,否則會繞來繞去把本身繞暈,技術都不是問題,重要的是思路;
代碼部分,命名符合規範,讓人看的懂是什麼意思,註釋也要全,讓人明白寫的什麼;
登陸模塊要好好研究一下,調用登陸方法去登陸,實現的原理和登陸時安全問題要考慮到;
技術上新用ModelMap這個對象,後臺存儲:map.put("名字","值"),前臺直接拿:var corpUsers = '${requestScope.名字}';
List Map json 互相轉換、傳值、接收值;
重發請求的GET、POST方法;
spring重定向、jsp重定向等。
微信ui地址:https://weui.io/
開發小白,若是有錯誤的地方盡請大佬們指出,謝謝