Java 第三方登录(微信 & QQ)

官方文档:

微信(appid和secret)微信网页开发 /网页授权

QQ(appid和appkey)QQ互联 | 网站开发流程

一、填写审核信息

1. 申请开发者身份,以企业名义申请。申请地址:

微信开放平台(微信开放平台

QQ互联(QQ互联官网首页

2. 填写网站审核资料

备案号查询网站(https://beian.miit.gov.cn/#/Integrated/recordQuery

网站名称、网站地址、主办单位名称、网站地址备案号需要和备案号网站查询结果一致。

注意

* 项目上线后才能审核通过。必须是正式环境才可以。

* 登录页需放置QQ图标,点击图标跳转至QQ登录页面(https://graph.qq.com/oauth2.0/authorize)

* 申请的网站回调域需和代码中的一致,否则会报错(QQ)

  申请的网站回调域接口不要求一致,但域名要求一致(微信)

* 微信申请需要注册账号,注册账号需要300元审核费

* 咨询客服链接:腾讯开放平台 OPEN.QQ.COM

二、代码开发(QQ登录)

1. 步骤一:用户点击QQ登录图标,跳转至QQ授权页面

<div class="login_qq">
  <a class="qq" href="${baseUrl}/qqLogin">  
    <img alt="QQ登录" title="QQ登录" src="${staticBaseUrl}/static/img/qq_icon.png">
  </a>
</div>
    //QQ审核获取的qppid和appkey
    @Value("${qq.appid}")
    private String appid;
    @Value("${qq.appkey}")
    private String appkey;
    /**
     * QQ登录
     * 步骤一:用户跳转至授权页面
     * @author 点点
     * @date 2021年6月17日
     */
    @RequestMapping(value = "/qqLogin" , method = {RequestMethod.POST , RequestMethod.GET})
    public String qqLogin(HttpServletRequest request, String display) throws IOException {
        String redirectUri = URLEncoder.encode(request.getAttribute("baseUrl")+"/getOpenId/qq","utf-8");
        String state = String.valueOf(UUID.randomUUID());
        cache.set(state, "", 30*1000);

        String codeUrl = "https://graph.qq.com/oauth2.0/authorize?" +
                "client_id=" + appid +
                "&redirect_uri=" + redirectUri +
                "&response_type=code" +
                "&scope=get_user_info" +
                "&display=" + display +
                "&state=" + state + "#qq_redirect";
        return "redirect:"+codeUrl;
    }

官方说明:

2. 步骤二:跳转授权页面获得code,通过code换取用户授权access_token

/**
     * QQ登录
     * 步骤二:同意授权,获得code,通过code换取网页授权access_token
     * @author 点点
     * @date 2021年6月17日
     */
    @RequestMapping(value = "/getOpenId/qq", method = {RequestMethod.POST,
            RequestMethod.GET})
    public String getQqOpenId(String code, String state,
                              HttpServletRequest request)
            throws IOException {
        //state校验,防止CSRF攻击
        String stateCache = cache.get(state, String.class);
        if (StringUtils.isBlank(stateCache)) {
            //跳转登录页,state校验不通过
            return "redirect:/login.html";
        }
        cache.del(state);
        //若用户禁止授权,则重定向后不会带上code参数,仅会带上state参数
        if(StringUtils.isBlank(code)) {
            //跳转登录页,用户未授权
            return "redirect:/login.html";
        }

        //申请的网站回调域需和代码中的一致,否则会报错(申请的网站回调域就是redirectUri)
        String redirectUri = URLEncoder.encode(
                request.getAttribute("baseUrl")+"/getOpenId/qq", "utf-8");
        //步骤二:通过code获取access_tokens
        String atUrl = "https://graph.qq.com/oauth2.0/token?" +
                "grant_type=authorization_code" +
                "&client_id=" + appid +
                "&client_secret=" + appkey +
                "&code=" + code +
                "&redirect_uri=" + redirectUri +
                "&fmt=json";

        String atResult = HttpUtils.sendGet(atUrl);
        JSONObject atObj = JSONObject.parseObject(atResult);
        String access_token = atObj.getString("access_token");
        if (StringUtils.isBlank(access_token)) {
            //跳转登录页,获取access_tokens失败
            return "redirect:/login.html";
        }

        //步骤三:通过access_tokens获取openid
        String openidUrl = "https://graph.qq.com/oauth2.0/me?" +
                "access_token=" + access_token +
                "&fmt=json";

        String openidResult = HttpUtils.sendGet(openidUrl);
        if (StringUtils.isBlank(openidResult)) {
            //跳转登录页,获取openid失败
            return "redirect:/login.html";
        }

        JSONObject openidObj = JSONObject.parseObject(openidResult);
        String openid = openidObj.getString("openid");

        //1.校验该用户是否已注册:
        User user = this.userService.getModelByQqOpenid(openid);
        if (user == null) {
            //跳转到获取手机号页面(用户手机号码必填且唯一,不需要的可省略该步骤)
            //注册方式registerType:3-QQ登录
            String param = "access_token="+access_token+"&openid="+openid+"&registerType=3";
            return "redirect:/settingPhone.html?" + param;
        }
        //2.登录
        //2.1 登录校验
        User userModel = userService.loginCheck(user);
        if (userModel == null) {
            //跳转登录页,账号已锁定
            return "redirect:/login.html";
        }
        //2.2 登录
        userService.login(userModel);

        //登陆成功,跳转首页
        return "redirect:/index.html";

    }

3. 步骤四:通过access_token和openid,获取用户信息

 /**
     * QQ登录(第三方注册)
     * 步骤四:通过access_token和openid,获取用户信息
     * @author 点点
     * @date 2021年6月17日
     */
    @RequestMapping(value = "/getUserInfo" , method = RequestMethod.POST)
    public APIResult<String> getUserInfo(String access_token, String openid,
                                         String phone, String verificationCode)
            throws IOException {
        //1.校验
        // 校验手机号

        //2. 注册
        //步骤四:通过access_token和openid,获取用户信息
        String infoUrl = "https://graph.qq.com/user/get_user_info?" +
                "access_token=" + access_token +
                "&openid=" + openid +
                "&oauth_consumer_key=" + appid;

        String infoResult = HttpUtils.sendGet(infoUrl);
        JSONObject jsonObject = JSONObject.parseObject(infoResult);
        //jsonObject.getString("nickname"); 昵称
        //jsonObject.getString("figureurl_1"); 头像
        //jsonObject.getString("gender");  性别
        //if (StringUtils.isBlank(nickname)) {
        //    return APIResult.error("页面失效");
        //}

        User user = this.userService.qqRegister(openid, phone);

        //2.登录
        //2.1 登录校验
        User userModel = userService.loginCheck(user);
        if (userModel == null) {
            return APIResult.error("账号已锁定");
        }

        //2.2 登录
        userService.login(userModel);

        return APIResult.ok("登录成功");
    }

三、调试

由于是正式环境,导致每次调试需要重新发包,很不方便。有以下两种调试方式:

    1. 将正式环境域名映射到本地,即可本地调试。

    2. 如果是客户方环境无法映射,则可在“步骤二:跳转授权页面获得code”时,将数据重新请求到本地进行调试,但是需要写两套代码,也比较麻烦。

四、代码开发(微信登录)

(偷个小懒)

1. 微信和QQ代码几乎一致,将qq的关键字替换为wx(注意区分大小写哦~)

2. 步骤一:用户点击WX登录图标,跳转至WX授权页面

String url = "https://open.weixin.qq.com/connect/qrconnect?" +
                "appid=" + appid +
                "&redirect_uri=" + redirectUri +
                "&response_type=code" +
                "&scope=snsapi_login" +
                "&state=" + state + "#wechat_redirect";

3. 步骤二:通过code获取access_tokens

String atUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?" +
                    "appid=" + appid +
                    "&secret=" + secret +
                    "&code=" + code +
                    "&grant_type=authorization_code";

4. 步骤三:通过access_token和openid,获取用户信息

String infoUrl = "https://api.weixin.qq.com/sns/userinfo?" +
                "access_token=" + access_token +
                "&openid=" + openid +
                "&lang=zh_CN";

5. 用户信息部分字段

{   
  "openid": "OPENID",
  "nickname": NICKNAME,
  "sex": 1, //用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
  "province":"PROVINCE",
  "city":"CITY",
  "country":"COUNTRY",
  "headimgurl":"https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
  "privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
  "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}

如果有更好的调试方法或代码有改进之处,欢迎大家留言交流~


版权声明:本文为Dawn____Dawn原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。