SpringBoot项目中引入QQ第三方登录教程,超详细

Java 5个月前 达西克
2,290 0 0

准备

开始前先准备好以下东西

手,备案好的域名,需要引入第三方登录的网站半成品

开发者审核

如果是首次开始弄QQ的第三方登录需要先进行开发者的信息填写和审核

  1. 前往QQ互联官网
    QQ互联官网
  2. 填写开发者资料,需要与站点的备案信息保持一致,否则在审核的时候容易出现驳回的情况。
    SpringBoot项目中引入QQ第三方登录教程,超详细
  3. QQ登录之后申请处在右上角头像这里
    SpringBoot项目中引入QQ第三方登录教程,超详细

网站审核

这里是最恶心的,为了弄这个被驳回了无数次SpringBoot项目中引入QQ第三方登录教程,超详细,等了好久才弄下来。最常见的驳回原因有以下几个

  • LOGO不符合标准
  • 网站名称和简介与备案信息不一致
  • 网站未放置QQ图标正常跳转或者报错。

下面说下对应的解决方法

  • 第一点我也是很懵逼,它的标准具体到底是什么搞不清楚,不行的话就多换几个logo的样式提交上去。
  • 第二点一般就是跟网站的备案信息不符合了,尤其是站点名称必须保持一致,简介也尽量是保持一致的。

第三点是要完成部分代码了,需要在网站的登录页面放置QQ图标。且完成能跳出弹框到QQ登录到页面或者是当前窗口跳转,但这里还没有完成审核,会跳转到一个如下图所示的界面,即为成功
SpringBoot项目中引入QQ第三方登录教程,超详细

功能代码

我这里是介绍的是的当前窗口跳转登录界面的方式,后文中以127.0.0.1的ip为参考,实际使用中则是域名

首先引入okhttp的maven依赖

<!-- okhttp依赖-->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.14.1</version>
</dependency>

页面上添加QQ登录图标按钮,我这里是使用的layui

<a  href="${ctx}/loginByQQ"  class="layui-row wiki-qq xh-social-item" style="margin-right: 10px"></a>

后台登录重定向跳转接口,跳转到QQ的第三方登录页面,审核前需要完成到这一步再进行提交。

@RequestMapping("/loginByQQ")
    public void loginByQQ(HttpServletRequest request, HttpServletResponse response) throws IOException {
        String state = new Date().toString();
        request.getSession().setAttribute("state", state);
        String url = qqConnection.getUrl(state);
        response.sendRedirect(url);
    }

配置文件,这里填写QQ互联上给的id和key还有回调地址

#APP ID
QQAppID=xxxxxx
#APP kEY
QQAppKEY=xxxx
#回调地址
redirectUri=http://127.0.0.1:8000/qqcalback

创建一个封装好的工具类获取用户的登录信息以及获取openId

package com.darcy.blog.config;

import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.security.auth.message.callback.SecretKeyCallback;
import java.io.IOException;
import java.util.Date;

@Component
@Slf4j
public class QQConnection {
    //    读取appid
    @Value("${QQAppID}")
    private String QQAppID;
    @Value("${QQAppKEY}")
//    读取appkey
    private String QQAppKEY;
    //读取redirect_uri
    @Value("${redirectUri}")
    private String redirectUri;

//    第一步:获取 QQ登录按钮url 几乎等于手动拼接 无太大意义

    public String getUrl(String state){
        String response_type = "code";
        String client_id = QQAppID;
        String redirect_uri = redirectUri;
        //client端的状态值。用于第三方应用防止CSRF攻击。
        String url = String.format("https://graph.qq.com/oauth2.0/authorize" +
                "?response_type=%s&client_id=%s&redirect_uri=%s&state=%s", response_type, client_id, redirect_uri, state);
        //String url = "https://graph.qq.com/oauth2.0/authorize?display=pc&response_type=code&client_id=" + QQAppID+"&redirect_uri="+redirect_uri+"&state=200";
        System.out.println("第一步:获取QQ登录按钮的url="+url);
        return url;
    }
    /*
    第三步:根据前一步得到的 Authorization Code 获取access token
     */
    public String getAccessToken(String code){
        String accessTaken="";
        String url = "https://graph.qq.com/oauth2.0/token?display=pc&grant_type=authorization_code&client_id="+QQAppID+"&client_secret="+QQAppKEY+"&redirect_uri="+redirectUri+"&code="+code;
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();
        try (Response response = client.newCall(request).execute()) {
            assert response.body() != null;
            String responseString = response.body().string();
            log.info("responseString=="+responseString);
            accessTaken = responseString.split("=")[1].split("&")[0];
            System.out.println("第三步:获取QQ互联返回的accessTaken="+accessTaken);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return accessTaken;
    }

    /*
    第四步:根据得到的access token 获取用户的 openID 和 oauth_consumer_key:申请QQ登录成功后,分配给应用的openid(对当前网站应用唯一,可用于检测是否为同一用户的凭证)
     */
    public JSONObject getUserOpenID(String accessToken){
        JSONObject userInfo = new JSONObject();
        String urlProvideByQQConnection = "https://graph.qq.com/oauth2.0/me";
        String requestUrl =urlProvideByQQConnection+"?access_token="+accessToken;
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(requestUrl)
                .build();
        try (Response response = client.newCall(request).execute()) {
            assert response.body() != null;
            String UserInfoString = response.body().string().split(" ")[1];
            userInfo = JSONObject.parseObject(UserInfoString);
            System.out.println("第四步:获取QQ互联返回的openid和分配给应用的appid:"+userInfo);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return userInfo;
    }

    /*
    第五步:根据 access_token、oauth_consumer_key(上一步返回的client_id)、openid 获取用户有效信息 (昵称、头像等) 返回json对象
     */
    public JSONObject getUserInfo(String access_token , String oauth_consumer_key , String openid ){
        JSONObject userRealInfo = new JSONObject();
        String urlProvideByQQConnection= "https://graph.qq.com/user/get_user_info?";
        String requestUrl = urlProvideByQQConnection+"access_token="+access_token+"&oauth_consumer_key="+oauth_consumer_key+"&openid="+openid;
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(requestUrl)
                .build();
        try (Response response = client.newCall(request).execute()) {
            assert response.body() != null;
            String UserRealInfoString = response.body().string();
            userRealInfo = JSONObject.parseObject(UserRealInfoString);
            System.out.println("第五步:获取QQ互联返回的用户有效信息:"+userRealInfo);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return userRealInfo;
    }
}

登录回调后处理接口

@RequestMapping("/qqcalback")
    public ModelAndView qqLogin(@RequestParam("code")String code , @RequestParam("state") String state , HttpServletRequest request){
    //我这里是以登陆成功处理完成之后重定向跳转首页的形式。可根据情况进行调整
        ModelAndView modelAndView = new ModelAndView("redirect:/");
        String authorization_code = request.getParameter("code");
        if (authorization_code != null && !authorization_code.trim().isEmpty()) {
            //        第三步 获取access token
            String accessToken = qqConnection.getAccessToken(authorization_code);
//        第四步 获取登陆后返回的 openid、appid 以JSON对象形式返回
            JSONObject userInfo = qqConnection.getUserOpenID(accessToken);
            log.info("QQ登录:" + userInfo.toJSONString());
//        第五步获取用户有效(昵称、头像等)信息  以JSON对象形式返回
            String oauth_consumer_key = userInfo.getString("client_id");
            String openid = userInfo.getString("openid");
            System.out.println("第二步:获取QQ互联返回的code="+code);
             JSONObject userRealInfo = qqConnection.getUserInfo(accessToken,oauth_consumer_key,openid);
             //userRealInfo即为拿到的json形式的用户信息,后面根据自己的登录逻辑进行处理
            }
    }

到这就大功告成了,再来说下拿到的参数

返回参数

参数说明 描述
ret 返回码
msg 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。
nickname 用户在QQ空间的昵称。
figureurl 大小为30×30像素的QQ空间头像URL。
figureurl_1 大小为50×50像素的QQ空间头像URL。
figureurl_2 大小为100×100像素的QQ空间头像URL。
figureurl_qq_1 大小为40×40像素的QQ头像URL。
figureurl_qq_2 大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100x100的头像,但40x40像素则是一定会有。
gender 性别。 如果获取不到则默认返回”男”
阿里云爆款特惠服务器
版权声明:达西克 发表于 2022年 9月 18日 pm6:45。
转载请注明:SpringBoot项目中引入QQ第三方登录教程,超详细 | 达西克

相关文章

暂无评论

暂无评论...