【QQ互聯】三、QQ授權第三方登錄

當我們創建的 QQ 互聯應用成功後,我們便可以開始使用該應用來實現 QQ 互聯

  • 一、獲取 APP ID 和 APP Key

1、在 QQ 互聯官網首頁找到“我的應用”
我的應用
2、點擊應用,進入詳情
獲取appid和appkey
這樣,我們就獲取到了 APP ID 和 APP Key

  • 二、QQ 授權登錄進行開發

1、將 APP ID 、APP Key,以及該應用的信息放入項目中的配置文件中,我使用的是SpringBoot,我放在了 application.yml 配置文件中
qq互聯信息

  • 二、添加 Maven 依賴,在 pom.xml 文件中,我們需要加入以下依賴信息
<!-- 網絡請求 -->
<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.5.6</version>
</dependency>

其他依賴,請自行加入

  • 三、在頁面放置 QQ 授權登錄的 DOM 元素
<a th:href="@{qq/auth}" class="link" title="騰訊QQ登錄"><i class="layui-icon">&#xe676;</i></a>
  • 四、創建 QQ 授權登錄的 Controller,QqController.java

1、從配置文件中獲取 QQ 互聯信息

/**
     * QQ互聯中提供的 appid 和 appkey
     */
    @Value("${qq.oauth.appid}")
    public String APPID;
    @Value("${qq.oauth.appkey}")
    public String APPKEY;
    @Value("${qq.oauth.url}")
    public String URL;

定義三個變量,接收 QQ 互聯的信息

2、登錄按鈕點擊後的接口

/**
     * 請求授權頁面
     */
    @GetMapping(value = "/auth")
    public String qqAuth(HttpSession session) {
        // 用於第三方應用防止CSRF攻擊
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        session.setAttribute("state", uuid);

        // Step1:獲取Authorization Code
        String url = "https://graph.qq.com/oauth2.0/authorize?response_type=code" +
                "&client_id=" + APPID +
                "&redirect_uri=" + URLEncoder.encode(URL) +
                "&state=" + uuid;

        return PasswordUtils.redirectTo(url);
    }

QQ 互聯的接口文檔中建議我們在授權登錄時傳入一個加密的數據防止被攻擊,我們傳入了UUID,最後重定向到授權頁面
QQ授權頁面

3、我們在授權頁面,登錄了 QQ 賬號,並同意授權後,就回到了我們創建應用是設置的回調地址裏面了

/**
     * 授權回調
     */
    @GetMapping(value = "/callback")
    public String qqCallback(HttpServletRequest request) throws Exception {
        HttpSession session = request.getSession();
        // 得到Authorization Code
        String code = request.getParameter("code");
        // 我們放在地址中的狀態碼
        String state = request.getParameter("state");
        // 驗證信息
        String uuid = (String) session.getAttribute("state");

        // 驗證信息我們發送的狀態碼
        if (null != uuid) {
            // 狀態碼不正確,直接返回登錄頁面
            if (!uuid.equals(state)) {
                return PasswordUtils.redirectTo("/login");
            }
        }

        // Step2:通過Authorization Code獲取Access Token
        String url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code" +
                "&client_id=" + APPID +
                "&client_secret=" + APPKEY +
                "&code=" + code +
                "&redirect_uri=" + URL;
        String access_token = QqHttpClient.getAccessToken(url);

        // Step3: 獲取回調後的openID
        url = "https://graph.qq.com/oauth2.0/me?access_token=" + access_token;
        String openId = QqHttpClient.getOpenID(url);

        // Step4:獲取QQ用戶信息
        url = "https://graph.qq.com/user/get_user_info?access_token=" + access_token +
                "&oauth_consumer_key=" + APPID +
                "&openid=" + openId;

        // 得到用戶信息
        JSONObject jsonObject = QqHttpClient.getUserInfo(url);
        // 根據openid在數據庫中查找是否存在此用戶
        UserInfo userInfo = userInfoService.getUserInfo(openId, Const.UserCategory.USER_CATEGORY_QQ);
        // 如果存在此用戶,則檢查該用戶是否合法,返回首頁
        if (null != userInfo) {
            if (2 == userInfo.getStatus()) {
                return PasswordUtils.redirectTo("/login");
            } else {
                session.setAttribute(Const.SYSTEM_USER_SESSION, userInfo);
                // 新增一條登錄日誌
                loginLogService.saveLoginLog(userInfo.getId(), ServletUtils.getServletPojo(request));
            }
        }
        // 該用戶不存在,則需要新建一個用戶保存到數據庫中,並登錄
        else {
            // 隨機生成賬戶
            String loginAccount = Const.Number.NUMBER_ONE + RandomUtils.getCurrentTimeMillis(Const.Number.NUMBER_EIGHT);
            // 隨機生成鹽值
            String salt = PasswordUtils.getSalt();
            // 加密後的密碼,默認密碼123456
            String password = PasswordUtils.getMd5("123456", loginAccount, salt);
            // 性別
            String sexStr = (String) jsonObject.get("gender");
            int sex = Const.Sex.SEX_SECRECY;
            // 男
            if (Const.Sex.SEX_MAN_STR.equals(sexStr)) {
                sex = Const.Sex.SEX_MAN;
            }
            // 女
            else if (Const.Sex.SEX_WOMAN_STR.equals(sexStr)) {
                sex = Const.Sex.SEX_WOMAN;
            }
            // 保存新用戶
            userInfoService.saveUserInfo(loginAccount, jsonObject.getString("nickname"), "", password, salt, jsonObject.getString("figureurl_qq_2"), sex, openId, Const.UserCategory.USER_CATEGORY_QQ);
            // 根據openid在數據庫中查找是否存在此用戶
            userInfo = userInfoService.getUserInfo(openId, Const.UserCategory.USER_CATEGORY_QQ);
            // 將當前用戶保存到session中去
            session.setAttribute(Const.SYSTEM_USER_SESSION, userInfo);
            // 新增一條登錄日誌
            loginLogService.saveLoginLog(userInfo.getId(), ServletUtils.getServletPojo(request));
        }
        return PasswordUtils.redirectTo("/success");
    }

以上代碼,從我自己的項目中拷貝而來,如果你直接使用,你需要對其業務代碼進行修改

4、第三步代碼中所用到的網絡接口方法,我放在了 QqHttpClient.java 文件中,主要有三個方法

/**
     * 獲取Access Token
     */
    public static String getAccessToken(String url) throws IOException {
        CloseableHttpClient client = HttpClients.createDefault();
        String token = null;

        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = client.execute(httpGet);
        HttpEntity entity = response.getEntity();

        if (entity != null) {
            String result = EntityUtils.toString(entity, "UTF-8");
            if (result.indexOf("access_token") >= 0) {
                String[] array = result.split("&");
                for (String str : array) {
                    if (str.indexOf("access_token") >= 0) {
                        token = str.substring(str.indexOf("=") + 1);
                        break;
                    }
                }
            }
        }

        httpGet.releaseConnection();
        return token;
    }

    /**
     * 獲取openID
     */
    public static String getOpenID(String url) throws IOException {
        JSONObject jsonObject = null;
        CloseableHttpClient client = HttpClients.createDefault();

        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = client.execute(httpGet);
        HttpEntity entity = response.getEntity();

        if (entity != null) {
            String result = EntityUtils.toString(entity, "UTF-8");
            jsonObject = parseJSONP(result);
        }

        httpGet.releaseConnection();

        if (jsonObject != null) {
            return jsonObject.getString("openid");
        } else {
            return null;
        }
    }

    /**
     * 獲取QQ用戶信息
     */
    public static JSONObject getUserInfo(String url) throws IOException {
        JSONObject jsonObject = null;
        CloseableHttpClient client = HttpClients.createDefault();

        HttpGet httpGet = new HttpGet(url);
        HttpResponse response = client.execute(httpGet);
        HttpEntity entity = response.getEntity();

        if (entity != null) {
            String result = EntityUtils.toString(entity, "UTF-8");
            jsonObject = JSONObject.parseObject(result);
        }

        httpGet.releaseConnection();

        return jsonObject;
    }
    
    /**
     * 轉換json對象
     */
    private static JSONObject parseJSONP(String jsonp) {
        int startIndex = jsonp.indexOf("(");
        int endIndex = jsonp.lastIndexOf(")");
        String json = jsonp.substring(startIndex + 1, endIndex);
        return JSONObject.parseObject(json);
    }

以上,就是完成 QQ 授權登錄的過程

  • 五、總結

總結來說如圖所示
qq授權登錄示意圖
如您在閱讀中發現不足,歡迎留言!!!

下一篇:

【QQ互聯】四、分享至QQ、新浪微博

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章