標籤:
一、什麼是OAuth
OAuth: OAuth(開放授權)是一個開放標準,允許使用者授權第三方網站訪問他們儲存在另外的服務提供者上的資訊,而不需要將使用者名稱和密碼提供給第三方網站或分享他們資料的所有內容。
QQ登入OAuth2.0:對於使用者相關的OpenAPI(例如擷取使用者資訊,動態同步,照片,日誌,分享等),為了保護使用者資料的安全和隱私,第三方網站訪問使用者資料前都需要顯式的向使用者徵求授權。
二、接入方式
網站可通過以下兩種方式接入:
(1)使用QQ互聯提供的SDK包,使用者體驗統一,只需要修改少量代碼,不需要理解驗證授權流程,需要快速接入QQ登入的網站和行動裝置 App可選用此方法。
QQ互聯提供JavaScript,PHP,Java等多個版本的SDK,詳見:SDK下載
QQ登入JS SDK詳見:JS SDK使用說明
(2)根據QQ登入OAuth2.0協議,自主開發,此方法自訂程度較高,需要與現有系統進行整合的網站和行動裝置 App可選用此方法。(我們這裡用第二種)
三、接入流程
QQ登入OAuth2.0總體處理流程如下:
Step1:申請接入,擷取appid和apikey;
Step2:開發應用,並設定共同作業者帳號進行測試聯調;
Step3:放置QQ登入按鈕;
Step4:通過使用者登入驗證和授權,擷取Access Token;
Step5:通過Access Token擷取使用者的OpenID;
Step6:調用OpenAPI,來請求訪問或修改使用者授權的資源。
四、核心代碼
qqinfo.json中放的是app_id, app_secret和跳轉地址,下面這段代碼需要jackson和httpclient包,注意引入。
//頁面返回資訊 String nickname = "Unkown"; //json處理工具 ObjectMapper objectMapper = new ObjectMapper(); //請求執行工具 CloseableHttpClient httpclient = HttpClients.createDefault(); //請求發送資訊 HttpPost httppost; HttpEntity reqEntity; CloseableHttpResponse responseEntity; //請求傳回值處理需要的臨時變數 BufferedReader reader; StringBuilder tempSB; String tempLine; //處理結果 Map<String, String> map; try { Map<String, String> param = objectMapper.readValue(new File(request.getServletContext().getRealPath("/") + "webfile/qqinfo.json"), Map.class); String codeStr = request.getParameter("code"); //如果code或json資訊為空白直接退出 if (codeStr != null && param != null) { //第一次請求 httppost = new HttpPost("https://graph.qq.com/oauth2.0/token"); reqEntity = MultipartEntityBuilder.create().addPart("code", new StringBody(codeStr, ContentType.TEXT_PLAIN)).addPart("client_id", new StringBody(param.get("qq_id"), ContentType.TEXT_PLAIN)).addPart("client_secret", new StringBody(param.get("qq_secret"), ContentType.TEXT_PLAIN)).addPart("redirect_uri", new StringBody(param.get("qq_url"), ContentType.TEXT_PLAIN)).addPart("grant_type", new StringBody("authorization_code", ContentType.TEXT_PLAIN)).build(); httppost.setEntity(reqEntity); responseEntity = httpclient.execute(httppost); //從第一次請求的傳回值中拿到token String accessToken = null; tempSB = new StringBuilder(); reader = new BufferedReader(new InputStreamReader(responseEntity.getEntity().getContent())); while ((tempLine = reader.readLine()) != null) { tempSB.append(tempLine); } String[] results = tempSB.toString().split("&"); for (String result : results) { String[] tmp = result.split("="); if (tmp.length == 2 && "access_token".equals(tmp[0])) { accessToken = tmp[1]; } } //如果token拿不到直接退出 if (accessToken != null) { //第二次請求 httppost = new HttpPost("https://graph.qq.com/oauth2.0/me"); reqEntity = MultipartEntityBuilder.create().addPart("access_token", new StringBody(accessToken, ContentType.TEXT_PLAIN)).build(); httppost.setEntity(reqEntity); responseEntity = httpclient.execute(httppost); //從第二次請求的傳回值中拿到openid tempSB = new StringBuilder(); reader = new BufferedReader(new InputStreamReader(responseEntity.getEntity().getContent())); while ((tempLine = reader.readLine()) != null) { tempSB.append(tempLine); } map = objectMapper.readValue(tempSB.toString().substring(tempSB.toString().indexOf("{"), tempSB.toString().indexOf("}") + 1), Map.class); //如果openid拿不到則直接退出 if (map.get("client_id") != null && map.get("openid") != null) { //第三次請求 httppost = new HttpPost("https://graph.qq.com/user/get_user_info"); reqEntity = MultipartEntityBuilder.create().addPart("access_token", new StringBody(accessToken, ContentType.TEXT_PLAIN)).addPart("openid", new StringBody(map.get("openid"), ContentType.TEXT_PLAIN)).addPart("oauth_consumer_key", new StringBody(map.get("client_id"), ContentType.TEXT_PLAIN)).build(); httppost.setEntity(reqEntity); responseEntity = httpclient.execute(httppost); //從第三次請求的傳回值中拿到使用者資訊(nickname) tempSB = new StringBuilder(); reader = new BufferedReader(new InputStreamReader(responseEntity.getEntity().getContent())); while ((tempLine = reader.readLine()) != null) { tempSB.append(tempLine); } map = objectMapper.readValue(tempSB.toString(), Map.class); nickname = map.get("nickname"); } } } } catch (Exception e) { e.printStackTrace(); }
<Java> QQ登入OAuth開發簡介