第三方登录--QQ登录--单体应用
从零玩转第三方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登录--单体应用的更多相关文章
- 第三方登录 QQ登录 人人网登录 新浪微博登录
http://www.pp6.cn/Index.aspx http://www.pp6.cn/Login.aspx 网站有自己的账号系统,这里使用的第三方登录仅仅是获取第三方账号的唯一id,昵称,性别 ...
- 第三方登录 ----QQ登录
学习之前,请大家先看一下oAuth协议. 首先呢,我们进入QQ互联的官方网站 http://connect.qq.com登入我们自己的QQ号,没有QQ号的小伙伴可以忽略本篇博文分享!
- 安卓Android第三方登录-QQ登录
要实现QQ第三方登录,其实只需要一个封装类:QQLoginManager 几乎 三行代码 就实现QQ登录功能 这里先给出Github开源项目地址,项目下有详细的使用说明 下面就开始详细说一说怎么实 ...
- PHP第三方登录——QQ登录
主要内容 简单回顾OAuth协议基本原理 接入QQ登录的前置条件以及开放平台账号申请 引入官方SDK SDK参数配置 SDK核心方法解读 整合QQ登录SDK到Web应用中 SDK优化 调用API的开发 ...
- 第三方登陆--QQ登陆--单体应用
从零玩转第三方QQ登陆 下面有源码 前后端分离版本 一样的思路 https://www.cnblogs.com/Yangbuyi/p/13194007.html 第三方GITEE登陆 https:// ...
- 第三方账号登录--QQ登录,以及QQ微博账号登录
在QQ登陆测试的时候,刚申请正常登陆,但是由于app未上线,或许是腾讯升级造成的个别时候QQ登陆无法成功会提示下图代码,功能上没啥问题,已经达到 测试效果了.附上腾讯错误代码图(大家测试QQ登陆的时候 ...
- 第三方登录(QQ登录)开发流程详解
原文:http://www.cnblogs.com/it-cen/p/4338202.html 近排由于工作的繁忙,已经一个星期没写博文做分享了,接下来我对网站接入第三方登录----QQ登录的实现逻辑 ...
- (转)第三方登录(QQ登录)开发流程详解
近排由于工作的繁忙,已经一个星期没写博文做分享了,接下来我对网站接入第三方登录----QQ登录的实现逻辑做一个详细的讲解. 对于整个流程的详细文档可以到QQ互联官网(http://wiki.conne ...
- Django商城项目笔记No.11用户部分-QQ登录1获取QQ登录网址
Django商城项目笔记No.11用户部分-QQ登录 QQ登录,亦即我们所说的第三方登录,是指用户可以不在本项目中输入密码,而直接通过第三方的验证,成功登录本项目. 若想实现QQ登录,需要成为QQ互联 ...
- qq登录,新浪微博登录 ,接口开发
给linux命令在线中文手册加了,qq登录和新浪微博登录,认证用的是auth2.0,并且用了js api和php api相结合的方式来做的.个人觉得这种方式,兼顾安全和人性化.以前写过一篇关于申请的博 ...
随机推荐
- 教你2种方法,将iOS设备通过MQTT协议连接到华为云物联网平台
本文分享自华为云社区<如何将iOS设备通过MQTT协议连接到华为云物联网平台: Flutter和Swift两种方法>,作者: 张俭 . 前言 当今时代,物联网技术正逐步改变我们的生活和工作 ...
- 一文搞懂 OTP 双因素认证
GitHub 在 2023 年 3 月推出了双因素认证(two-factor authentication)简称 2FA,并且承诺所有在 GitHub 上贡献的开发者在 2023 年底前启用双因素认证 ...
- How to parse OR AND within text
假设你有一行 String condition = "A or B and C"; 语句,请问怎么做才能变成一行真正的逻辑表达式(能在计算机中运行计算)? Resolution 声 ...
- 创业团队建设与管理mooc【第二次中期测验】
mo'o 第二次中期测验 返回 已经超过规定的测试次数或提交截止时间已过.你可以作为自我学习进行测验,但提交的结果将无法获得学分. 1 单选(2分) PDCA循环中的P是指什么? 得分/总分 A. 处 ...
- 一行代码搞定 font-size 响应式
前言 公司要做大屏,但是大屏还要有个嵌在系统的版本,屏幕(iframe)小了但字体大了怎么办.网上找了很多代码都很长,个人参考了资料后实现了一个一行代码 font-size 响应式. TL;DR ht ...
- Arithmetic Progression 题解
Arithmetic Progression 题目大意 存在一个打乱了顺序的等差数列 \(a\),你可以询问不超过 \(60\) 次,每次可以以以下两种方式之一进行询问: 查询 \(a\) 中是否有严 ...
- Thread类 常用方法
3.6 start 与 run 调用 run public static void main(String[] args) { Thread t1 = new Thread("t1" ...
- 计算网络之MSTP协议与VRRP协议
一.MSTP协议 MSTP协议出现是基于STP协议和RSTP协议的,要了解MSTP协议就需要先了解其它两个协议 首先,STP协议是交换机生成树协议,它的出现主要是为了解决二层交换机环路的问题,当多个交 ...
- 神经网络入门篇:神经网络的梯度下降(Gradient descent for neural networks)
神经网络的梯度下降 在这篇博客中,讲的是实现反向传播或者说梯度下降算法的方程组 单隐层神经网络会有\(W^{[1]}\),\(b^{[1]}\),\(W^{[2]}\),\(b^{[2]}\)这些参数 ...
- 实例讲解C++连接各种数据库,包含SQL Server、MySQL、Oracle、ACCESS、SQLite 和 PostgreSQL、MongoDB 数据库
C++ 是一种通用的编程语言,可以使用不同的库和驱动程序来连接各种数据库.以下是一些示例代码,演示如何使用 C++ 连接 SQL Server.MySQL.Oracle.ACCESS.SQLite 和 ...