从零玩转第三方QQ登录

下面有源码

前后端分离版本

一样的思路

https://www.cnblogs.com/Yangbuyi/p/13194007.html

第三方GITEE登录

https://www.cnblogs.com/Yangbuyi/p/yangbuyi.html

oss对象存储超好玩

https://www.cnblogs.com/Yangbuyi/p/13493845.html

在真正开始对接之前,我们先来聊一聊后台的方案设计。既然是对接第三方登录,那就免不了如何将用户信息保存。首先需要明确一点的是,用户在第三方登录成功之后,

我们能拿到的仅仅是一个代表用户唯一身份的ID(微博是真实uid,QQ是加密的openID)以及用来识别身份的accessToken,当然还有昵称、头像、性别等有限资料,

对接第三方登录的关键就是如何确定用户是合法登录,如果确定这次登录的和上次登录的是同一个人并且不是假冒的。其实这个并不用我们特别操心,就以微博登录为例,

用户登录成功之后会回调一个code给我们,然后我们再拿code去微博那换取 accessToken ,如果这个code是用户乱填的,那这一关肯定过不了,所以,前面的担心有点多余,哈哈。

1. 认识Oauth2.0

现在很多网站都要不管是为了引流也好,为了用户方便也好一般都有第三方账号登陆的需求,今天以QQ登陆为例,来实现一个最简单的第三方登陆。

目前主流的第三方登录都是依赖的Oauth2.0实现的,最常见的就是在各种中小型网站或者App中的QQ登录,微信登录等等。所以我建议想要学习和实现第三方登录同学去了解下这个协议。

1.2 必须要域名并且进行备案

比如我的域名: https://yangbuyi.top/

因为腾讯有一个域名认证机制啥的。。。。。。

2.实名认证

QQ登录我们对接的是QQ互联,地址:https://connect.qq.com ,首先需要注册成为开发者并实名认证,需要手持身份证照片,具体就不讲了。

2.1、进行申请开发者身份

2.2 创建应用

进入应用管理页面创建应用,根据实际需要是创建网站应用还是移动应用,我这里是网站应用:



提交成功完步后等待客服审核即可

2.3. QQ登陆流程

2.4. 请求参数

3.前台准备

创建 home.html login.html



前端代码

## login.html

  <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body> <form action="/api/login/oauth">
<input type="submit" value="登陆">
</form>
</body>
</html>

home.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="">
<label class="">登陆成功</label>
<div class="">
<p th:text="'openID :' + ${map.qqOpenidDTO.openid}"></p> <p th:text="'用户名称 :' + ${map.user.nickname}"></p> 用户头像:
<img th:src="${map.user.figureurl_qq_1}" alt="">
<br>
<img th:src="${map.user.figureurl_qq_1}" alt="">
<img th:src="${map.user.figureurl_qq_2}" alt="">
ht </div>
</div> </body>
</html>

4. 后端实现

## pom依赖导入

  <!-- qq登陆集成 开始 -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.11</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.8</version>
</dependency> <dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpasyncclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
</dependency>
<!--json转换工具-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!--QQSDK-->
<dependency>
<groupId>net.gplatform</groupId>
<artifactId>Sdk4J</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<!-- qq登陆集成 结束 --> <!-- 模板 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

yml配置文件

server:
port: 8080 # QQ 登录 参数
oauth:
qq:
#你的appid
client_id: ????????
#你的appkey
client_secret: ????????
#你接收响应code码地址
redirect_uri: ????????
#腾讯获取code码地址
code_callback_uri: ????????
#腾讯获取access_token地址
access_token_callback_uri: ????????
#腾讯获取openid地址
openid_callback_uri: ????????
#腾讯获取用户信息地址
user_info_callback_uri: ???????? spring:
thymeleaf:
cache: false
suffix: .html

创建HttpsUtils

用于发送QQ服务器请求----请在gitee获取

创建QQ包当中的所有文件----请在gitee获取

QQDTO--- 用于存储QQ服务器返回来的参数

QQOpenidDTO--- 用来存储 access_token、openid

OAuthProperties--- 用于成为配置文件yml注入参数到QQProperties获取code码

QQProperties--- 用于存储访问QQ服务器必要的参数

5. 创建路由跳转

RequestController

@Controller
@Slf4j
public class RequestController {
// 登陆
@RequestMapping("login")
public String login() {
return "login";
} // 登陆成功跳转
@RequestMapping("home")
public String home() {
return "home";
} }

6.创建LoginController

package top.yangbuyi.controller;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.yangbuyi.QQ.OAuthProperties;
import top.yangbuyi.QQ.vo.QQDTO;
import top.yangbuyi.QQ.vo.QQOpenidDTO;
import top.yangbuyi.common.HttpsUtils; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID; /**
* @description: 杨不易网站:www.yangbuyi.top
* @program: qqlogindemo
* @ClassName: loginController
* @create: 2020-08-18 14:41
* @author: yangbuyi
* @since: JDK1.8
* @loginController: 第三方QQ登陆
**/ @Controller
@Slf4j
@RequestMapping("api")
public class loginController { /**
* 认证参数
*/
@Autowired
private OAuthProperties oauth; /**
* 调用QQ登陆接口
*
* @param response
*/
@GetMapping("/login/oauth")
public void loginQQ(HttpServletResponse response) {
/**
* 重定向
*/
try {
response.sendRedirect(oauth.getQQ().getCode_callback_uri() + //获取code码地址
"?client_id=" + oauth.getQQ().getClient_id()//appid
+ "&state=" + UUID.randomUUID() + //这个说是防攻击的,就给个随机uuid吧
"&redirect_uri=" + oauth.getQQ().getRedirect_uri() +//这个很重要,这个是回调地址,即就收腾讯返回的code码
"&response_type=code");
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 接收回调地址带过来的code码
* @param code
* @param request
* @return
*/
@GetMapping("/oauth2")
public String authorizeQQ(String code, HttpServletRequest request) {
HashMap<String, Object> params = new HashMap<>();
params.put("code", code);
params.put("grant_type", "authorization_code");
params.put("redirect_uri", oauth.getQQ().getRedirect_uri());
params.put("client_id", oauth.getQQ().getClient_id());
params.put("client_secret", oauth.getQQ().getClient_secret()); // 获取腾讯access token
/**
遍历拿到的数据:
access_token=6D45343586C39EAA1CFF016E081E4F3E
refresh_token=3CD8AD92C146A6154AF89DD1DEEA86BB
expires_in=7776000
*/
Map<String, String> reulsts = getAccess_token(params); //到这里access_token已经处理好了
//下一步获取openid,只有拿到openid才能拿到用户信息
String openidContent = HttpsUtils.doGet(oauth.getQQ().getOpenid_callback_uri() + "?access_token=" + reulsts.get("access_token")); System.out.println("openidContent: " + openidContent); //接下来对openid进行处理
//截取需要的那部分json字符串
String openid = openidContent.substring(openidContent.indexOf("{"), openidContent.indexOf("}") + 1);
Gson gson = new Gson();
//将返回的openid转换成DTO
QQOpenidDTO qqOpenidDTO = gson.fromJson(openid, QQOpenidDTO.class); //接下来说说获取用户信息部分
//登陆的时候去数据库查询用户数据对于openid是存在,如果存在的话,就不用拿openid获取用户信息了,而是直接从数据库拿用户数据直接认证用户,
// 否则就拿openid去腾讯服务器获取用户信息,并存入数据库,再去认证用户
//下面关于怎么获取用户信息,并登陆
params.clear();
params.put("access_token", reulsts.get("access_token"));//设置access_token
params.put("openid", qqOpenidDTO.getOpenid());//设置openid
params.put("oauth_consumer_key", qqOpenidDTO.getClient_id());//设置appid
//获取用户信息
String userInfo = HttpsUtils.doGet(oauth.getQQ().getUser_info_callback_uri(), params);
QQDTO qqDTO = gson.fromJson(userInfo, QQDTO.class);
// (正常情况下,在开发时候用openid作为用户名,再自己定义个密码就可以了)
try { /* 组装数据 */
HashMap<String, Object> map = new HashMap<>();
map.put("user", qqDTO);
map.put("qqOpenidDTO", qqOpenidDTO);
request.setAttribute("map", map);
log.info("user数据:{}" + qqDTO);
log.info("qqOpenidDTO数据:{}" + qqOpenidDTO);
return "home";
} catch (Exception e) {
e.printStackTrace();
return "login";
}
} /**
* 获取腾讯 access_token
*
* @return
*/
public Map<String, String> getAccess_token(HashMap<String, Object> params) {
// 认证地址
//获取access_token如:access_token=9724892714FDF1E3ED5A4C6D074AF9CB&expires_in=7776000&refresh_token=9E0DE422742ACCAB629A54B3BFEC61FF
String result = HttpsUtils.doGet(oauth.getQQ().getAccess_token_callback_uri(), params);
//对拿到的数据进行切割字符串
String[] strings = result.split("&");
//切割好后放进map
Map<String, String> reulsts = new HashMap<>();
for (String str : strings) {
String[] split = str.split("=");
if (split.length > 1) {
reulsts.put(split[0], split[1]);
}
}
return reulsts;
} }

7. 测试QQ登陆




项目源代码--- 请移步GITee

https://gitee.com/yangbuyi/bky_yby

第三方登录--QQ登录--单体应用的更多相关文章

  1. 第三方登录 QQ登录 人人网登录 新浪微博登录

    http://www.pp6.cn/Index.aspx http://www.pp6.cn/Login.aspx 网站有自己的账号系统,这里使用的第三方登录仅仅是获取第三方账号的唯一id,昵称,性别 ...

  2. 第三方登录 ----QQ登录

    学习之前,请大家先看一下oAuth协议. 首先呢,我们进入QQ互联的官方网站 http://connect.qq.com登入我们自己的QQ号,没有QQ号的小伙伴可以忽略本篇博文分享!

  3. 安卓Android第三方登录-QQ登录

    要实现QQ第三方登录,其实只需要一个封装类:QQLoginManager 几乎 三行代码 就实现QQ登录功能 这里先给出Github开源项目地址,项目下有详细的使用说明   下面就开始详细说一说怎么实 ...

  4. PHP第三方登录——QQ登录

    主要内容 简单回顾OAuth协议基本原理 接入QQ登录的前置条件以及开放平台账号申请 引入官方SDK SDK参数配置 SDK核心方法解读 整合QQ登录SDK到Web应用中 SDK优化 调用API的开发 ...

  5. 第三方登陆--QQ登陆--单体应用

    从零玩转第三方QQ登陆 下面有源码 前后端分离版本 一样的思路 https://www.cnblogs.com/Yangbuyi/p/13194007.html 第三方GITEE登陆 https:// ...

  6. 第三方账号登录--QQ登录,以及QQ微博账号登录

    在QQ登陆测试的时候,刚申请正常登陆,但是由于app未上线,或许是腾讯升级造成的个别时候QQ登陆无法成功会提示下图代码,功能上没啥问题,已经达到 测试效果了.附上腾讯错误代码图(大家测试QQ登陆的时候 ...

  7. 第三方登录(QQ登录)开发流程详解

    原文:http://www.cnblogs.com/it-cen/p/4338202.html 近排由于工作的繁忙,已经一个星期没写博文做分享了,接下来我对网站接入第三方登录----QQ登录的实现逻辑 ...

  8. (转)第三方登录(QQ登录)开发流程详解

    近排由于工作的繁忙,已经一个星期没写博文做分享了,接下来我对网站接入第三方登录----QQ登录的实现逻辑做一个详细的讲解. 对于整个流程的详细文档可以到QQ互联官网(http://wiki.conne ...

  9. Django商城项目笔记No.11用户部分-QQ登录1获取QQ登录网址

    Django商城项目笔记No.11用户部分-QQ登录 QQ登录,亦即我们所说的第三方登录,是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录本项目. 若想实现QQ登录,需要成为QQ互联 ...

  10. qq登录,新浪微博登录 ,接口开发

    给linux命令在线中文手册加了,qq登录和新浪微博登录,认证用的是auth2.0,并且用了js api和php api相结合的方式来做的.个人觉得这种方式,兼顾安全和人性化.以前写过一篇关于申请的博 ...

随机推荐

  1. Solution -「洛谷 P3600」随机数生成器

    Desciption Link. 给定一个值域在 \([1,x]\) 的长度为 \(n\) 的序列(由随机数构成),求给定一组区间中的最小值的最大值的期望. Solution 记: \[w=\max\ ...

  2. 新零售SaaS架构:面向中小连锁的SaaS系统整体规划

    零售企业的发展路径 零售企业的发展路径一般可分为以下几个阶段: 单店经营阶段:企业在一个地区或城市开设单个门店.这时,企业需要把精力放在了解当地市场和顾客需求上,这是积累经验和品牌知名度的重要环节.为 ...

  3. 最快速搭建个人服务器图床siuuuuu

    @ 目录 1.服务器准备 2.docker 安装 (1)通过命令行的方式 (2)宝塔面板上安装 3.开启端口访问 什么是docker 4.docker安装minio 什么是minio 5.配置mini ...

  4. 5.go语言函数提纲

    1 本篇前瞻 前端时间的繁忙,未曾更新go语言系列.由于函数非常重要,为此将本篇往前提一提,另外补充一些有关go新版本前面遗漏的部分. 需要恭喜你的事情是本篇学完,go语言中基础部分已经学完一半,这意 ...

  5. ESP32-MicroPython 开发环境

    Linux/Mac 下使用MicroPython开发ESP32 刷入固件 使用 esptool.py 将 MicroPython 刷入 ESP32 开发板涉及几个步骤. 1. 安装 esptool 如 ...

  6. 轻松掌握组件启动之Redis集群扩展秘籍:轻松扩容与缩容,释放高性能潜能

    扩展集群操作 扩容 在我们原始的集群基础上,我们决定增加一台主节点(8007)和一台从节点(8008),这样新增的节点将会在下图中以虚线框的形式显示在集群中. 1: 首先,在 /usr/local/r ...

  7. Python - 字典3

    修改字典项 您可以通过引用其键名来更改特定项的值: 示例,将 "year" 更改为 2018: thisdict = { "brand": "Ford ...

  8. 【Python微信机器人】第一篇:在windows11上编译python

    前言 我打算写一个系列,内容是将python注入到其他进程实现inline hook和主动调用.本篇文章是这个系列的第一篇,后面用到的案例是注入python到PC微信实现基本的收发消息.文章着重于py ...

  9. 如何在 Vue.js 中引入原子设计?

    本文为翻译文章,原文链接: https://medium.com/@9haroon_dev/introducing-atomic-design-in-vue-js-a9e873637a3e 前言 原子 ...

  10. ACAM 学习笔记 | 附 YbtOJ 全部题解

    怎么有人现在才学 ACAM 呢. 好像比 SAM 简单挺多啊,也不记得当时是哪里看不懂. AC 自动机() 自动 AC 机(✘) 概述 ACAM(Aho–Corasick Automaton),是用来 ...