【vue+nestjs】qq第三方授权登录【超详细】
项目场景:
前端使用vue3+ts 后端使用nestjs
1.申请appId,appKey
1.进入qq互联官网。创建应用

特别注意
1.在填写网站回调域时,需要你线上真实能访问的。不然审核不通过。我的回调地址是前端路由地址
2.如果你想本地调试,回调到你的线上地址。你可以在本地设置本地域名,做反向代理。我是用的是phpstudy,方向代理自己的线上域名。
如果你还是不明白,可以留言
2.代码演示
特别注意:
如果你跟我一样是前后端分离的模式开发的,应用回调地址填写的应该是你的前端路由地址。在你的前端页面获取code,把code值传给后端接口。后端接口通过code获取gitee用户信息。
代码演示
我的应用回调地址:http://localhost:8080/vuecms/qq
- 前端点击qq图标登录代码:
<div @click="handleToLogin('qq')">gitee
</div>const handleToLogin = (type:string)=>{window.location.href="http://localhost:3000/user/oauth/qq"
}
- http://localhost:3000/user/oauth/qq后端接口代码
@Get('/oauth/qq')async qqLogin(@Res() response: Response) {let appId = 你的appId;let redirectUrl = 你的回调地址;const state = Date.now()let scope = "get_user_info,list_album"return qqOauthConfig.authorizeUrl+`&client_id=${appId}&redirect_uri=${redirectUrl}&state=${state}&scope=${scope}`;}
- 回调地址前端代码
<template><div class="u-f u-f-ac u-f-ajc" style="width: 100%;height:100vh"><template v-if="isOauth"><el-resulticon="success"title="授权成功,跳转中..."></el-result></template><template v-else><el-resulticon="error"title="授权失败"></el-result></template></div>
</template><script setup lang="ts">import {useRoute,useRouter} from "vue-router";import {onMounted} from "@vue/runtime-core";import {requestGiteeLogin} from "@/network/common/oauthPage";import {setToken, setUserId, setUsername} from "@/utils/storage";import {handleGetCurInstance} from "@/utils/utils";import {ref} from "vue"let route = useRoute()let router = useRouter()let query = route.query;let {model} = handleGetCurInstance()let isOauth = ref(true)onMounted(()=>{//获取返回的code,通过code对后端发起请求,获取qq用户信息let {code,state} = query;let form = {code,state}requestQQLogin(form).then(res=>{let {data,code,message} = res;if(code==200){setToken(data.token)setUserId(data.id)setUsername(data.username)window.location.href="/"}else{model.handleMsg(message,"warning")isOauth.value =false;}})})
</script>
- requestQQLogin请求的后端代码
// qq 的认证配置
export const qqOauthConfig = {cid: "",//gitee官网设置获取secret: "",redirectURL: '',//gitee官网配置进行填写authorizeUrl: 'https://graph.qq.com/oauth2.0/authorize?response_type=code',getAccessTokenUrl: 'https://graph.qq.com/oauth2.0/token?grant_type=authorization_code',openId:"https://graph.qq.com/oauth2.0/me",qqUserAPI:"https://graph.qq.com/user/get_user_info"
};
//qq登录@Post('/oauth/qqLogin')async getQQInfo(@Body() qqLoginDto:QqLoginDto,@IpAddress() clientIp: string) {let {code,operationSystem,browser} = giteeLoginDtolet accessToken:any = await this.handleGetQQAccessToken(code)if(!accessToken.data){return this.msgService.fail("code过期,请重新登录")}let giteeInfo:any = await this.getQQInfoByAccessToken(accessToken.data.accessToken,accessToken.data.appId);if(!giteeInfo.data){return this.msgService.fail("获取qq账号信息失败")}let { nickname } = giteeInfo.data.userData;let clientId = 0;let qqId = sysConfigEnum.qqLoginConfig + JSON.parse(JSON.stringify(giteeInfo.data.openid));//判断qq是否有关联账号。如果有就登陆,没有就新创建一个账号let userNum = await this.userEntity.createQueryBuilder().where({ qqId:qqId }).getCount()let username;//没有账号,注册帐号if(userNum<=0){let roleData = await this.roleEntity.createQueryBuilder().where({roleName:"试用角色"}).getOne()username = handleGetCode(8);username = await this.handleGetUsername(username);let originalPwd = handleGetCode(8);let password = JSON.parse(JSON.stringify(originalPwd))password = securityMd5(password)let userData;try {userData = await this.userEntity.createQueryBuilder().insert().values({username,originalPwd,password,qqId:qqId,roleId:roleData.id}).execute();}catch (error) {throw new HttpException(error,HttpStatus.SERVICE_UNAVAILABLE)}clientId = userData.identifiers[0]["id"]}else{let userData = await this.userEntity.createQueryBuilder().where({qqId:qqId}).getOne()username = userData.usernameclientId = userData.id;}let ip = handleDealIpv6ToIpv4(clientIp)let token = this.authService.createToken({id:clientId,username,ip})await this.updateUserInfoStatus(clientId,token,ip,operationSystem,browser)return {id:clientId,username,token}}//获取gitee的accessTokenasync handleGetQQAccessToken(code:string):Promise<resInterface>{let key = sysConfigEnum.qqLoginConfiglet data = await this.sysConfigService.handleGetSysData(key)if(!data.appId || !data.appKey || !data.redirectUrl){return {data:false,msg:""};}let appId = data.appId;let appKey = data.appKey;let redirectUrl = data.redirectUrl;//回调路劲获取codelet authData = await axios.get(qqOauthConfig.getAccessTokenUrl+`&code=${code}&client_id=${appId}&client_secret=${appKey}&redirect_uri=${redirectUrl}`).then(res=>{let resArr = res.data.split("&")let accessToken = resArr[0].split("=")[1]let expiresIn = resArr[1].split("=")[1]let refreshToken = resArr[2].split("=")[1]return {accessToken,expiresIn,refreshToken};}).catch(err=>{return err.data})if(authData?.error){return this.msgService.commonRes(false,authData?.error?.error_description);}else{return this.msgService.commonRes({accessToken:authData?.accessToken,appId},"");}}//通过access_token获取gitee信息async getQQInfoByAccessToken(accessToken: boolean | string,appId:string){let authData = await axios.get(qqOauthConfig.openId+`?access_token=${accessToken}`).then(res=>{let data = JSON.parse(res.data.substring(9, res.data.length-3))let clientId = data.client_id;let openid = data.openid;return {clientId,openid};}).catch(err=>{return err.data})if(authData?.error){return this.msgService.commonRes(false,authData?.error?.error_description);}let userData = await axios.get(qqOauthConfig.qqUserAPI+`?access_token=${accessToken}&oauth_consumer_key=${appId}&openid=${authData.openid}`).then(res=>{return res.data;}).catch(err=>{return err.data})if(userData?.error){return this.msgService.commonRes(false,authData?.error?.error_description);}else{return this.msgService.commonRes({userData,openid:authData.openid},"");}}
3.特别注意
如果以上步骤都没问题。需要把本地测试回调地址改为线上路径
如果你还是不懂,你可以克隆下我的项目。开源免费。如果对你有帮助,给我一个star就行了
https://gitee.com/derekgo/vue-cms_xg
✨ 踩坑不易,还希望各位大佬支持一下 \textcolor{gray}{踩坑不易,还希望各位大佬支持一下} 踩坑不易,还希望各位大佬支持一下
📃 个人主页: \textcolor{green}{个人主页:} 个人主页: 沉默小管
📃 个人网站: \textcolor{green}{个人网站:} 个人网站: 沉默小管
📃 个人导航网站: \textcolor{green}{个人导航网站:} 个人导航网站: 沉默小管导航网
📃 我的开源项目: \textcolor{green}{我的开源项目:} 我的开源项目: vueCms.cn
🔥 技术交流 Q Q 群: 837051545 \textcolor{green}{技术交流QQ群:837051545} 技术交流QQ群:837051545
👍 点赞,你的认可是我创作的动力! \textcolor{green}{点赞,你的认可是我创作的动力!} 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向! \textcolor{green}{收藏,你的青睐是我努力的方向!} 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富! \textcolor{green}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!
如果有不懂可以留言,我看到了应该会回复
如有错误,请多多指教
相关文章:
【vue+nestjs】qq第三方授权登录【超详细】
项目场景: 前端使用vue3ts 后端使用nestjs 1.申请appId,appKey 1.进入qq互联官网。创建应用 特别注意 1.在填写网站回调域时,需要你线上真实能访问的。不然审核不通过。我的回调地址是前端路由地址 2.如果你想本地调试,回调到你的线上地址。你可以在本…...
经典卷积神经网络 - VGG
使用块的网络 - VGG。 使用多个 3 3 3\times 3 33的要比使用少个 5 5 5\times 5 55的效果要好。 VGG全称是Visual Geometry Group,因为是由Oxford的Visual Geometry Group提出的。AlexNet问世之后,很多学者通过改进AlexNet的网络结构来提高自己的准确…...
系统集成测试(SIT)/系统测试(ST)/用户验收测试(UAT)
文章目录 单元测试集成测试系统测试用户验收测试黑盒测试白盒测试压力测试性能测试容量测试安全测试SIT和UAT的区别 单元测试 英文 unit testing,缩写 UT。测试粒度最小,一般由开发小组采用白盒方式来测试,主要测试单元是否符合“设计”。 …...
Android Gradle8.0以上多渠道写法以及针对不同渠道导入包的方式,填坑!
目录 多渠道的写法 针对多渠道引用不同的包 There was a failure while populating the build operation queue: Could not stat file E:\xxxx\xxxx\xxxx\app\src\UAT\libsUAT\xxx-provider(?)-xx.aar 最近升级了Gradle8.3之后,从Groovy 迁移到 Kotlinÿ…...
hdlbits系列verilog解答(向量门操作)-14
文章目录 一、问题描述二、verilog源码三、仿真结果 一、问题描述 构建一个具有两个 3 位输入的电路,用于计算两个向量的按位 OR、两个向量的逻辑 OR 以及两个向量的逆 (NOT)。将b反相输出到out_not上半部分,将a 的反相输出到out…...
工厂模式(初学)
工厂模式 1、简单工厂模式 是一种创建型设计模式,旨在通过一个工厂类(简单工厂)来封装对象的实例化过程 运算类 public class Operation { //这个是父类private double num1; //运算器中的两个值private double num2;public double getNu…...
python试题实例
背景: 在外地出差,突然接到单位电话,让自己出一些python考题供新人教育训练使用,以下是10道Python编程试题及其答案: 1.试题:请写一个Python程序,计算并输出1到100之间所有偶数的和。 答案&am…...
Java Heap Space问题解析与解决方案(InsCode AI 创作助手)
Heap Space问题是Java开发中常见的内存溢出问题之一,我们需要理解其原因和表现形式,然后通过优化代码、增加JVM内存和使用垃圾回收机制等方法来解决。 一、常见报错 java.lang.OutOfMemoryError: Java heap space二、Heap Space问题的原因 对象创建过…...
基于遥感影像的分类技术(监督/非监督和面向对象的分类技术)
遥感图像分类技术 “图像分类是将土地覆盖类别分配给像素的过程。例如,类别包括水、城市、森林、农业和草原。”前言 – 人工智能教程 什么是遥感图像分类? 遥感图像分类技术的三种主要类型是: 无监督图像分类监督图像分类基于对象的图像分析…...
插入兄弟元素 insertAfter() 方法
insertAfter() 方法在被选元素后插入 HTML 元素。 提示:如需在被选元素前插入 HTML 元素,请使用 insertBefore() 方法。 语法 $(content).insertAfter(selector)例子: $("<span>Hello world!</span>").insertAfter(…...
【C++项目】高并发内存池第二讲中心缓存CentralCache框架+核心实现
CentralCache 1.框架介绍2.核心功能3.核心函数实现介绍3.1SpanSpanList介绍3.2CentralCache.h3.3CentralCache.cpp3.4TreadCache申请内存函数介绍3.5慢反馈算法 1.框架介绍 回顾一下ThreadCache的设计: 如图所示,ThreadCache设计是一个哈希桶结构&…...
Git基础教程
一、Git简介 1、什么是Git? Git是一个开源的分布式版本控制系统,用于敏捷高效地处理任何或大或小的项目。 Git是Linus Torvalds为了帮助管理Linux内核开发而开发的一个开放源代码的版本控制软件。 Git与常用的版本控制工具CVS、Subversion等不同&#…...
stm32外部时钟为12MHZ,修改代码适配
代码默认是8MHZ的,修改2个地方: 第一个地方是这个文件的这里: 第二个地方是找到这个函数: 修改第二个地方的这里:...
【数据结构】八大排序
目录 1. 排序的概念及其作用 1.1 排序的概念 1.2 排序运用 1.3 常见的排序算法 2. 常见排序算法的实现 2.1 插入排序 2.1.1 基本思想 2.1.2 直接插入排序 2.1.3 希尔排序(缩小增量排序) 2.2 选择排序 2.2.1 基本思想 2.2.2 直接选择排序 2.2…...
MYSQL(事务+锁+MVCC+SQL执行流程)理解
一)事务的特性: 一致性:主要是在数据层面来说,不能说执行扣减库存的操作的时候用户订单数据却没有生成 原子性:主要是在操作层面来说,要么操作完成,要么操作全部回滚; 隔离性:是自己的事务操作自己的数据,不会受到到其…...
解密一致性哈希算法:实现高可用和负载均衡的秘诀
解密一致性哈希算法:实现高可用和负载均衡的秘诀 前言第一:分布式系统中的数据分布问题,为什么需要一致性哈希算法第二:一致性hash算法的原理第三:一致性哈希算法的优点和局限性第四:一致性哈希算法的安全性…...
Python脚本:让工作自动化起来
Python是一种流行的编程语言,以其简洁和易读性而闻名。它提供了大量的库和模块,使其成为自动化各种任务的绝佳选择。 本文将探讨Python脚本及其代码,可以帮助您自动化各种任务并提高工作效率。无论您是开发人员、数据分析师还是只是想简化工…...
香港科技大学广州|可持续能源与环境学域博士招生宣讲会—广州大学城专场!!!(暨全额奖学金政策)
香港科技大学广州|可持续能源与环境学域博士招生宣讲会—广州大学城专场!!!(暨全额奖学金政策) “面向未来改变游戏规则的——可持续能源与环境学域” ���专注于能源环…...
uni-app:多种方法写入图片路径
一、文件在前端文件夹中 1、相对路径引用 从当前文件所在位置开始寻找图片文件的路径。../../ 表示返回两级目录,即从当前文件所在的 wind.vue 所在的位置开始向上回退两级。接着,进入 static 目录,再进入 look 目录,最后定位到 …...
共谋工业3D视觉发展,深眸科技以自研解决方案拓宽场景应用边界
随着中国工业领域自动化程度逐渐攀升,“机器换人”这一需求进一步提升。在传统2D工业视觉易受环境光干扰、无法进一步获取物体深度信息的限制条件下,工业3D视觉凭借着更强的空间和深度感知能力,以及通过点云数据获取物体距离和三维坐标信息的…...
装饰模式(Decorator Pattern)重构java邮件发奖系统实战
前言 现在我们有个如下的需求,设计一个邮件发奖的小系统, 需求 1.数据验证 → 2. 敏感信息加密 → 3. 日志记录 → 4. 实际发送邮件 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
