【第三方互联】三、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、新浪微博

发布了63 篇原创文章 · 获赞 66 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40065776/article/details/104497177