時間:2023-05-20 18:16:02 | 來源:網(wǎng)站運營
時間:2023-05-20 18:16:02 來源:網(wǎng)站運營
Java實現(xiàn)QQ登錄和微博登錄:uid
,QQ是加密的openId
)以及用來識別身份的accessToken
,當然還有昵稱、頭像、性別等有限資料,對接第三方登錄的關(guān)鍵就是如何確定用戶是合法登錄,如果確定這次登錄的和上次登錄的是同一個人并且不是假冒的。其實這個并不用我們特別操心,就以微博登錄為例,用戶登錄成功之后會回調(diào)一個code給我們,然后我們再拿code去微博那換取accessToken
,如果這個code是用戶亂填的,那這一關(guān)肯定過不了,所以,前面的擔心有點多余,哈哈。OpenUser
表關(guān)聯(lián)起來,判斷用戶是否登錄時把OpenUser
的鑒權(quán)也加進去就OK了。OpenUser
表用來存放第三方登錄用戶,主要字段如下:accessToken
寫入cookie肯定是不安全的,因為accessToken
相當于是第三方網(wǎng)站的臨時密碼,被別人竊取了就可以隨意拿來干壞事了。可以在用戶登錄成功之后我們自己生成一個token,這樣的token即使泄露了頂多就是被人拿來隨意評論,損失不大,但是如果accessToken被泄露了,以微博為例,人家可以利用這個accessToken
隨意發(fā)微博、刪微博、加關(guān)注等等,很危險。當然,如果不想token泄露的話也可以通過綁定IP等方式來限制。appId
和appKey
。/** * 封裝一個居中打開新窗口的方法 */function openWindow(url, width, height){ width = width || 600; height = height || 400; var left = (window.screen.width - width) / 2; var top = (window.screen.height - height) / 2; window.open(url, "_blank", "toolbar=yes, location=yes, directories=no, status=no, menubar=yes, scrollbars=yes, resizable=no, copyhistory=yes, left="+left+", top="+top+", width="+width+", height="+height);}function qqLogin(){ var qqAppId = '424323422'; // 上面申請得到的appid var qqAuthPath = 'http://www.test.com/auth'; // 前面設(shè)置的回調(diào)地址 var state = 'fjdslfjsdlkfd'; // 防止CSRF攻擊的隨機參數(shù),必傳,登錄成功之后會回傳,最好后臺自己生成然后校驗合法性 openWindow(`https://graph.qq.com/oauth2.0/authorize?response_type=token&client_id=${qqAppId}&redirect_uri=${encodeURIComponent(qqAuthPath)}&state=${state}`);}
然后會打開一個授權(quán)頁面,這個頁面大家應該都熟悉:#
后面,URL地址中的hash值好像不會被傳到后臺(貌似是這樣,如有不正確歡迎評論指正),所以只能寫一個下面這樣的臨時頁面:/** * QQ鑒權(quán) * @param request * @param response * @throws Exception */@RequestMapping("/authqq")public void authQQ(HttpServletRequest request, HttpServletResponse response) throws Exception{ // QQ登錄有點特殊,參數(shù)放在#后面,后臺無法獲取#后面的參數(shù),只能用JS做中間轉(zhuǎn)換 String html = "<!DOCTYPE html>" + "<html lang=/"zh-cn/">" + "<head>" + " <title>QQ登錄重定向頁</title>" + " <meta charset=/"utf-8/"/>" + "</head>" + "<body>" + " <script type=/"text/javascript/">" + " location.href = location.href.replace('#', '&').replace('auth_qq', 'auth_qq_redirect');" + " </script>" + "</body>" + "</html>"; response.getWriter().print(html);}
3.5. 獲取openIdQQ號+appId
唯一的,換句話說同一個QQ號登錄2個不同appId時獲取到的openId是不同的。順便說一句,QQ登錄的相關(guān)接口做的還真夠“隨便”的,全部都是最簡單的get請求,所以對接起來非常順利。// 根據(jù)accessToken換取openId// 錯誤示例:callback( {"error":100016,"error_description":"access token check failed"} );// 正確示例:callback( {"client_id":"10XXXXX49","openid":"CF2XXXXXXXX9F4C"} );String result = HttpsUtil.get("https://graph.qq.com/oauth2.0/me?access_token=" + accessToken);Map<String, Object> resp = parseQQAuthResponse(result); // 這個方法就是把結(jié)果轉(zhuǎn)MapInteger errorCode = (Integer)resp.get("error");String errorMsg = (String)resp.get("error_description");String openId = (String)resp.get("openid");if(errorCode != null) return new ErrorResult(errorCode, "獲取QQ用戶openId失?。?#34;+errorMsg);
3.6. 獲取用戶頭像昵稱等信息// 獲取用戶昵稱、頭像等信息,{ret: 0, msg: '', nickname: '', ...} ret不為0表示失敗result = HttpsUtil.get("https://graph.qq.com/user/get_user_info?access_token="+accessToken+"&oauth_consumer_key="+appId+"&openid="+openId);resp = JsonUtil.parseJsonToMap(result);Integer ret = (Integer)resp.get("ret");String msg = (String)resp.get("msg");if(ret != 0) return new ErrorResult("獲取用戶QQ信息失?。?#34;+msg);// 用戶昵稱可能存在4個字節(jié)的utf-8字符,MySQL默認不支持,直接插入會報錯,所以過濾掉String nickname = StringUtil.filterUtf8Mb4((String)resp.get("nickname")).trim(); // 這個方法可以自行百度// figureurl_qq_2=QQ的100*100頭像,figureurl_2=QQ 100&100空間頭像,QQ頭像不一定有,空間頭像一定有String avatar = (String)resp.get("figureurl_qq_2");if(StringUtil.isBlank(avatar)) avatar = (String)resp.get("figureurl_2");String gender = (String)resp.get("gender");
3.7. 注意事項utf8mb4
,直接插入會報錯,所以需要過濾掉;function weiboLogin(){ let weiboAppId = '432432'; let weiboAuthPath = 'http://www.test.com/authweibo'; openWindow(`https://api.weibo.com/oauth2/authorize?client_id=${weiboAppId}&response_type=code&redirect_uri=${encodeURIComponent(weiboAuthPath)}`);}
微博登錄有一個好處,第一次登錄需要授權(quán),后面第二次登錄時只會一閃而過自動就登錄成功了,都不需要點一下,用戶體驗非常好,看下圖:String params = "client_id=" + appId + "&client_secret=" + appSecret + "&grant_type=authorization_code" + "&redirect_uri=" + URLUtil.encode(authPath) + "&code=" + code;// 用code換取accessTokenString result = HttpsUtil.post("https://api.weibo.com/oauth2/access_token", params);Map<String, Object> resp = JsonUtil.toObject(result, new TypeReference<Map<String, Object>>(){});Integer errorCode = (Integer)resp.get("error_code");String error = (String)resp.get("error");String errorMsg = (String)resp.get("error_description");if(errorCode != null && errorCode != 0) return new ErrorResult(errorCode, error + (errorMsg==null?"":errorMsg));String accessToken = (String)resp.get("access_token");String uid = (String)resp.get("uid"); // 這個uid就是微博用戶的唯一用戶ID,可以通過這個id直接訪問到用戶微博主頁int expires = (Integer)resp.get("expires_in"); // 有效期,單位秒
4.5. 獲取用戶頭像等信息// 用uid和accessToken換取用戶信息String result = HttpsUtil.get("https://api.weibo.com/2/users/show.json?access_token="+accessToken+"&uid="+uid);Map<String, Object> resp = JsonUtil.toObject(result, new TypeReference<Map<String, Object>>(){});errorCode = (Integer)resp.get("error_code");error = (String)resp.get("error");errorMsg = (String)resp.get("error_description");if(errorCode != null && errorCode != 0) return new ErrorResult(errorCode, error + (errorMsg==null?"":errorMsg));String nickname = (String)resp.get("screen_name");// 微博180*180高清頭像String avatar = (String)resp.get("avatar_large");String gender = (String)resp.get("gender");gender = "m".equals(gender) ? "男" : ("f".equals(gender) ? "女" : "");
至此涉及第三方的東西都完了,剩下的就是用戶自己保存到數(shù)據(jù)庫、寫入token、保存session、以及鑒權(quán)接口開發(fā)了。作者:我是小茗同學
鏈接:https://www.cnblogs.com/liuxianan/p/java-qq-weibo-login.html
來源:博客園
關(guān)鍵詞:實現(xiàn)
微信公眾號
版權(quán)所有? 億企邦 1997-2025 保留一切法律許可權(quán)利。