Java 实现 qq 登录

准备工作

1.云服务器

2.备案的域名

3.本地调试需要修改hosts文件,将域名映射到127.0.0.1

一、申请QQ互联,并成为开发者

QQ互联:https://connect.qq.com/index.html

登录后,点击头像,进入认证页面,填写信息,等待审核。

审核通过后,点击创建应用

审核通过后,就可以使用APP ID 和 APP Key

二、编写java代码

项目结构

yml配置

server:  port: 80 qq:  oauth:    http: //QQ互联中填写的网站地址

导入pom依赖

<!--httpclient--><dependency>    <groupId>org.apache.httpcomponents</groupId>    <artifactId>httpclient</artifactId>    <version>4.5.6</version></dependency><!--阿里 JSON--><dependency>    <groupId>com.alibaba</groupId>    <artifactId>fastjson</artifactId>    <version>1.2.47</version></dependency>

QQController

package com.ck.blog.controller; import com.alibaba.fastjson.JSONObject;import com.ck.blog.exception.StateErrorException;import com.ck.blog.utils.QQHttpClient;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.GetMapping; import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import java.net.URLEncoder;import java.util.UUID; /** * @author ck * @create 2019-05-18 20:32 */@Controllerpublic class QQController {      @Value("${qq.oauth.http}")    private String http;     /**     * 发起请求     * @param session     * @return     */    @GetMapping("/qq/oauth")    public String qq(HttpSession session){        //QQ互联中的回调地址        String backUrl = http + "/qq/callback";         //用于第三方应用防止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=" + QQHttpClient.APPID +                "&redirect_uri=" + URLEncoder.encode(backUrl) +                "&state=" + uuid;         return "redirect:" + url;    }     /**     * QQ回调     * @param request     * @return     */    @GetMapping("/qq/callback")    public String qqcallback(HttpServletRequest request) throws Exception {        HttpSession session = request.getSession();        //qq返回的信息:http://graph.qq.com/demo/index.jsp?code=9A5F************************06AF&state=test        String code = request.getParameter("code");        String state = request.getParameter("state");        String uuid = (String) session.getAttribute("state");         if(uuid != null){            if(!uuid.equals(state)){                throw new StateErrorException("QQ,state错误");            }        }          //Step2:通过Authorization Code获取Access Token        String backUrl = http + "/qq/callback";        String url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code"+                "&client_id=" + QQHttpClient.APPID +                "&client_secret=" + QQHttpClient.APPKEY +                "&code=" + code +                "&redirect_uri=" + backUrl;         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="+ QQHttpClient.APPID +                "&openid=" + openid;         JSONObject jsonObject = QQHttpClient.getUserInfo(url);         //也可以放到Redis和mysql中        session.setAttribute("openid",openid);  //openid,用来唯一标识qq用户        session.setAttribute("nickname",(String)jsonObject.get("nickname")); //QQ名        session.setAttribute("figureurl_qq_2",(String)jsonObject.get("figureurl_qq_2")); //大小为100*100像素的QQ头像URL         return "redirect:/home";    }}

QQHttpClient

package com.ck.blog.utils; import com.alibaba.fastjson.JSONObject;import org.apache.http.HttpEntity;import org.apache.http.HttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils; import java.io.IOException; /** * @author ck * @create 2019-05-18 20:32 * QQ工具类(主要用于解析QQ返回的信息) */public class QQHttpClient {    //QQ互联中提供的 appid 和 appkey    public static final String APPID = "xxxxxxxx";     public static final String APPKEY = "xxxxxxxxxx";      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返回信息:access_token=FE04************************CCE2&expires_in=7776000&refresh_token=88E4************************BE14    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;    }    //qq返回信息:callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID"} ); 需要用到上面自己定义的解析方法parseJSONP    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返回信息:{ "ret":0, "msg":"", "nickname":"YOUR_NICK_NAME", ... },为JSON格式,直接使用JSONObject对象解析    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;    }}

IndexController

package com.ck.blog.controller; import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.GetMapping; import javax.servlet.http.HttpSession; /** * @author ck * @create 2019-05-18 20:31 */@Controllerpublic class IndexController {     @GetMapping("/index")    public String index(){        return "index";    }     @GetMapping("/home")    public String home(HttpSession session, Model model){        String openid = (String) session.getAttribute("openid");        String nickname = (String) session.getAttribute("nickname");        String figureurl_qq_2 = (String) session.getAttribute("figureurl_qq_2");         model.addAttribute("openid",openid);        model.addAttribute("nickname",nickname);        model.addAttribute("figureurl_qq_2",figureurl_qq_2);         return "home";    }}

index.html

<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <title>登录页</title></head><body><a href="/qq/oauth">QQ授权登录</a></body></html>

home.html

<!DOCTYPE html><html lang="en" xmlns:th="http://www.thymeleaf.org"><head>    <meta charset="UTF-8">    <title>QQ授权成功</title></head><body><div>    openid:[[${openid}]]</div><div>    nickName:[[${nickname}]]</div><div>    <img th:src="${figureurl_qq_2}"></div></body></html>

效果图

本文分享自微信公众号 - 好好学java(SIHAIloveJAVA),作者:全栈开发者社区

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-09-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 高并发之并发容器,了解多少(从入门到超神)

    在上面已经提到过ConcurrentHashMap,ConcurrentHashMap相比Hashtable能够进一步提高并发性,其原理图如下:

    好好学java
  • Java基于百度API的图片文字识别(支持中文,英文和中英文混合)

    具体文档:http://ai.baidu.com/docs#/OCR-API/e1bd77f3

    好好学java
  • 学多线程的看过来,带你学习多线程中断机制

    当我们点击某个杀毒软件的取消按钮来停止查杀病毒时,当我们在控制台敲入quit命令以结束某个后台服务时……都需要通过一个线程去取消另一个线程正在执行的任务。Jav...

    好好学java
  • SpringBoot-05-之上传文件

    张风捷特烈
  • 一款直击痛点的优秀http框架,让我超高效率完成了和第三方接口的对接

    因为业务关系,要和许多不同第三方公司进行对接。这些服务商都提供基于http的api。但是每家公司提供api具体细节差别很大。有的基于RESTFUL规范,有的基于...

    小小詹同学
  • Flask 使用json或者jsonify返回json响应数据的方法

    在前后端分离的时代,后端一般返回前端的数据就是json格式的响应数据。 而json格式的响应数据其实实际上就是一个字符串。

    Devops海洋的渔夫
  • Task 1_补充 深度学习概念

    这些Layer都是由一个个神经元组成,每个神经元都接受多个输入,并产生一个输出,就好像人的神经元突触一样。神经元在接收输入时,会各自乘以一定的权重(有时候...

    平凡的学生族
  • oeasy教您玩转linux010102查看发行版

    只靠 linux内核,咱们无法做任何事情,只有内核和各种应用程序在一起,咱们才能使用.

    oeasy
  • VMware15更新后克隆Centos7发现网卡起不来了

    TrueDei
  • 大话 Select、Poll、Epoll

    提到select、poll、epoll相信大家都耳熟能详了,三个都是IO多路复用的机制,可以监视多个描述符的读/写等事件。

    黄日成

扫码关注云+社区

领取腾讯云代金券