从零玩转第三方QQ登陆

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

我们能拿到的仅仅是一个代表用户唯一身份的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.前台准备

/** * 封装一个居中打开新窗口的方法 */ function openWindow(url, width, height) { width = width || 600; height = height || 400; var left = (window.screen.width - width) / 2; var top = (window.screen.height - height) / 2; var win =window.open(url, "_blank", "toolbar=yes, location=yes, directories=no, status=no, menubar=yes, scrollbars=yes, resizable=no, copyhistory=yes, left=" + left + ", top=" + top + ", width=" + width + ", height=" + height); console.log(win) }

3.1 使用 随便点击按钮进行调用这个 qq函数

3.2 点击访问后端 登陆方法

4. 后端实现

package top.yangbuyi.system.controller;

import com.google.gson.Gson;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import top.yangbuyi.system.common.ActiveUser;
import top.yangbuyi.system.common.Constant;
import top.yangbuyi.system.common.HttpsUtils;
import top.yangbuyi.system.common.WebUtils;
import top.yangbuyi.system.config.QQ.OAuthProperties;
import top.yangbuyi.system.config.QQ.vo.QQDTO;
import top.yangbuyi.system.config.QQ.vo.QQOpenidDTO; import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID; /**
* description: 杨不易网站 :www.yangbuyi.top
* program: yangbuyi-erp-2020
* ClassName: QQController
* create: 2020-06-24 17:17
*
* @author: yangbuyi
* @since: JDK1.8
**/ @RestController
@RequestMapping("api")
public class QQController { @Autowired
private OAuthProperties oauth;
private static final Logger logger = LoggerFactory.getLogger(QQController.class); /**
* 调用QQ登陆接口
*
* @param response
*/
@GetMapping("/login/oauth")
public String loginQQ(HttpServletResponse response) {
/**
* 重定向
*/
// response.sendRedirect();//授权模式,授权码模式 System.out.println(
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"
); return 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"; } //接收回调地址带过来的code码
@GetMapping("/oauth2")
public String authorizeQQ(Map msg, String code, HttpServletResponse response) {
HashMap 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=9724892714FDF1E3ED5A4C6D074AF9CB&expires_in=7776000&refresh_token=9E0DE422742ACCAB629A54B3BFEC61FF
String result = HttpsUtils.doGet(oauth.getQQ().getAccess_token_callback_uri(), params);
//对拿到的数据进行切割字符串
String[] strings = result.split("&");
//切割好后放进map
Map reulsts = new HashMap();
for (String str : strings) {
String[] split = str.split("=");
if (split.length > 1) {
reulsts.put(split[0], split[1]);
}
}
//到这里access_token已经处理好了
//下一步获取openid,只有拿到openid才能拿到用户信息
String openidContent = HttpsUtils.doGet(oauth.getQQ().getOpenid_callback_uri() + "?access_token=" + reulsts.get("access_token"));
//接下来对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作为密码(正常情况下,在开发时候用openid作为用户名,再自己定义个密码就可以了)
try {
System.out.println("用户信息:" + userInfo);
System.out.println(qqDTO);
// 获取主体
Subject subject = SecurityUtils.getSubject();
// SecurityUtils.getSubject().login(new UsernamePasswordToken(qqOpenidDTO.getOpenid(), Constant.DEFAULT_PWD));
System.out.println(qqOpenidDTO.getOpenid());
subject.login(new UsernamePasswordToken(qqDTO.getNickname(), Constant.DEFAULT_PWD)); String token = subject.getSession().getId().toString();
ActiveUser active = (ActiveUser) subject.getPrincipal();
params.put("token", token);
params.put("code", 200);
params.put("permissions", active.getPermissions());
params.put("username", active.getUser().getName());
params.put("usertype", active.getUser().getType());
System.out.println("Shiro认证成功");
} catch (Exception e) {
msg.put("msg", "第三方登陆失败,请联系管理!");
logger.error(e.getMessage());
System.out.println("Shiro认证失败");
// return new ResultObj(-1, "login.html");
// return "redirect:https://www.yangbuyi.top/login.html";
WebUtils.getHttpSession().setAttribute("params", params);
return "/login.html";
}
// return "redirect:" + "https://www.yangbuyi.top/"
// params WebUtils.getHttpSession().setAttribute("params", params);
// return "redirect:https://www.yangbuyi.top/index.html";
// return "getParams";
return "/index.html";
} /**
* 获取参数
*
* @return
*/
@RequestMapping("getParams")
public Object getParams() {
System.out.println(WebUtils.getHttpSession().getAttribute("params"));
return WebUtils.getHttpSession().getAttribute("params");
} }

第三方登陆--QQ登陆的更多相关文章

  1. 第三方登陆——QQ登陆详解

    申请地址 QQ互联:https://connect.qq.com/index.html 腾讯开放平台:https://open.tencent.com/ 注册账号 登陆 进入QQ互联,点击登陆 资料填 ...

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

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

  3. 第三方登陆-qq互联

    看到很多网站都有第三方登陆,使用业余时间自己也要实现一个第三方登陆的功能: 1.登陆qq互联的网站:https://connect.qq.com/index.html 2.点击头像进行资料申请 --- ...

  4. 网站第三方登陆(一) QQ登陆

    QQ 登陆是指,通过qq的用户名和密码,登录网站,不需要注册,网站的用户名和密码.如下图 一旦你授权了,就可以进入网站了,要实现这个效果 1.去qq互联平台(http://connect.qq.com ...

  5. phpcms V9实现QQ登陆OAuth2.0

    phpcmsV9使用的QQ登陆依然是OAuth1.0,但现在腾讯已经不审核使用OAuth1.0的网站了.这对于使用pc的站长来讲是一个无比巨大的坑.经过对phpcms论坛的一位同学做的插件进行修改,现 ...

  6. QQ互联OAuth2.0 .NET SDK 发布以及网站QQ登陆示例代码(转)

    OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容. QQ登录OAuth2 ...

  7. QQ互联OAuth2.0 .NET SDK 发布以及网站QQ登陆示例代码

    OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方网站访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方网站或分享他们数据的所有内容. QQ登录OAuth2 ...

  8. [iOS基础控件 - 3.1] QQ登陆界面

      A.storyboard 控件版 1.label 2.textfield      a.Keyboard Type           账号:Number Pad           密码:Num ...

  9. QQ登陆接口

    这次做了一个QQ登陆接口---简单记录一下 遇到一大坑-----QQ互联里面添加应用的时候,是网站应用,配置回调地址一定要配置  准确,到指定回调页面 否则会出现问题的.

随机推荐

  1. leetcode976之三角形最大周长

    题目描述: 给定由一些正数(代表长度)组成的数组 A,返回由其中三个长度组成的.面积不为零的三角形的最大周长. 如果不能形成任何面积不为零的三角形,返回 0. def largePara(A): A. ...

  2. Java实现 LeetCode 609 在系统中查找重复文件(阅读理解+暴力大法)

    609. 在系统中查找重复文件 给定一个目录信息列表,包括目录路径,以及该目录中的所有包含内容的文件,您需要找到文件系统中的所有重复文件组的路径.一组重复的文件至少包括二个具有完全相同内容的文件. 输 ...

  3. Java实现 蓝桥杯VIP 算法提高 P0404

    计算一个无符号整数的阿尔法乘积.对于一个无符号整数x来说,它的阿尔法乘积是这样来计算的:如果x是一个个位数,那么它的阿尔法乘积就是它本身:否则的话,x的阿尔法乘积就等于它的各位非0的数字相乘所得到的那 ...

  4. Java实现 蓝桥杯VIP 算法提高 任意年月日历输出

    算法提高 任意年月日历输出 时间限制:1.0s 内存限制:512.0MB 已知2007年1月1日为星期一. 设计一函数按照下述格式打印2007年以后(含)某年某月的日历,2007年以前的拒绝打印. 为 ...

  5. Java实现有向图强连通分量的Tarjan算法

    1 问题描述 引用自百度百科: 如果两个顶点可以相互通达,则称两个顶点强连通(strongly connected).如果有向图G的每两个顶点都强连通,称G是一个强连通图.有向图的极大强连通子图,称为 ...

  6. java实现第六届蓝桥杯星系炸弹

    星系炸弹 题目描述 在X星系的广袤空间中漂浮着许多X星人造"炸弹",用来作为宇宙中的路标. 每个炸弹都可以设定多少天之后爆炸. 比如:阿尔法炸弹2015年1月1日放置,定时为15天 ...

  7. TZOJ 车辆拥挤相互往里走

    102路公交车是crq经常坐的,闲来无聊,他想知道最高峰时车上有多少人,他发现这辆车只留一个门上下人,于是他想到了一个办法,上车时先数一下车上人员数目(crq所上的站点总是人不太多),之后就坐在车门口 ...

  8. window10下通过docker安装swoole,运行laravel-swoole服务

    最近公司压测一个接口,用laravel框架,业务逻辑就是从缓存中取数据,tps总是上不去,于是决定换下swoole来替换php-fpm,来处理php请求,tps比原来高了好几倍. 现在有个问题就是wi ...

  9. 利用struts2进行单个文件,批量文件上传,ajax异步上传以及下载

    利用struts2进行单个文件,批量文件上传,ajax异步上传以及下载 1.页面显示代码 <%@ page language="java" import="java ...

  10. TCP最简单的服务程序

    #include <time.h>#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#in ...