1、什麼是OAuthweb
OAuth: OAuth(開放受權)是一個開放標準,容許用戶受權第三方網站訪問他們存儲在另外的服務提供者上的信息,而不須要將用戶名和密碼提供給第三方網站或分享他們數據的全部內容。json
QQ登陸OAuth2.0:對於用戶相關的OpenAPI(例如獲取用戶信息,動態同步,照片,日誌,分享等),爲了保護用戶數據的安全和隱私,第三方網站訪問用戶數據前都須要顯式的向用戶徵求受權。
api
2、接入方式安全
網站可經過如下兩種方式接入:
(1)使用QQ互聯提供的SDK包,用戶體驗統一,只須要修改少許代碼,不須要理解驗證受權流程,須要快速接入QQ登陸的網站和移動應用可選用此方法。
QQ互聯提供JavaScript,PHP,Java等多個版本的SDK,詳見:SDK下載
QQ登陸JS SDK詳見:JS SDK使用說明app
(2)根據QQ登陸OAuth2.0協議,自主開發,此方法自定義程度較高,須要與現有系統進行整合的網站和移動應用可選用此方法。(咱們這裏用第二種)工具
3、接入流程post
QQ登陸OAuth2.0整體處理流程以下:測試
Step1:申請接入,獲取appid和apikey;網站
Step2:開發應用,並設置協做者賬號進行測試聯調;ui
Step3:放置QQ登陸按鈕;
Step4:經過用戶登陸驗證和受權,獲取Access Token;
Step5:經過Access Token獲取用戶的OpenID;
Step6:調用OpenAPI,來請求訪問或修改用戶受權的資源。
4、核心代碼
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(); }