【vue+nestjs】qq第三方授权登录【超详细】

项目场景:

前端使用vue3+ts 后端使用nestjs


1.申请appId,appKey

1.进入qq互联官网。创建应用
在这里插入图片描述
特别注意
1.在填写网站回调域时,需要你线上真实能访问的。不然审核不通过。我的回调地址是前端路由地址
2.如果你想本地调试,回调到你的线上地址。你可以在本地设置本地域名,做反向代理。我是用的是phpstudy,方向代理自己的线上域名。

如果你还是不明白,可以留言

2.代码演示

特别注意:
如果你跟我一样是前后端分离的模式开发的,应用回调地址填写的应该是你的前端路由地址。在你的前端页面获取code,把code值传给后端接口。后端接口通过code获取gitee用户信息。

代码演示

我的应用回调地址:http://localhost:8080/vuecms/qq

  1. 前端点击qq图标登录代码:
<div @click="handleToLogin('qq')">gitee
</div>const handleToLogin = (type:string)=>{window.location.href="http://localhost:3000/user/oauth/qq"
}
  1. 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}`;}
  1. 回调地址前端代码
<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>
  1. 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}{评论,你的意见是我进步的财富!} 评论,你的意见是我进步的财富!

如果有不懂可以留言,我看到了应该会回复
如有错误,请多多指教

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/167173.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

面试算法31:最近最少使用缓存

题目 请设计实现一个最近最少使用&#xff08;Least Recently Used&#xff0c;LRU&#xff09;缓存&#xff0c;要求如下两个操作的时间复杂度都是O&#xff08;1&#xff09;。 get&#xff08;key&#xff09;&#xff1a;如果缓存中存在键key&#xff0c;则返回它对应的值…

基于Django与深度学习的股票预测系统 计算机竞赛

文章目录 0 前言1 课题背景2 实现效果3 Django框架4 数据整理5 模型准备和训练6 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **基于Django与深度学习的股票预测系统 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff…

Redis基本命令和常用数据类型

文章目录 前言一、Redis简介二、基本操作1.赋值2.取值3.切换数据库4.查看数据库所有键&#xff08;key&#xff09;5.查看键值类型6.移动键值到其他数据库7.设置键值生存时间&#xff08;两种&#xff09;8.查看键值生存时间9.查看当前数据库大小10.判断键是否存在11.清空当前数…

基于ResNet34的花朵分类

一.数据集准备 新建一个项目文件夹ResNet&#xff0c;并在里面建立data_set文件夹用来保存数据集&#xff0c;在data_set文件夹下创建新文件夹"flower_data"&#xff0c;点击链接下载花分类数据集https://storage.googleapis.com/download.tensorflow.org/example_i…

英语什么时候加s和es

名词变复数一般情况下加s&#xff0c;以s,x,ch,sh结尾加es。一个名词如果表示一个或一样东西&#xff0c;它取单数形式&#xff0c;如果表示两个或更多的这类东西&#xff0c;则需要用名词复数形式。 1 以s,x,sh,ch结尾的词&#xff0c;加es。 2 以辅音字母&#xff08;除a/e/…

钢铁异常分类 few-shot 问题 小陈读paper 钢铁2

很清爽的 abstract 给出链接 前面的背景意义 其实 是通用的 这里替大家 整理一吓吓 1 缺陷分类在钢铁表面缺陷检测中 有 意义。 2 大多数缺陷分类模型都是基于完全监督的学习&#xff0c; 这需要大量带有图像标签的训练数据。 在工业场景中收集有缺陷的图像是非常困难…

C++11——lambda表达式

文章目录 1. C98对自定义类型的排序2. lambda表达式语法2.1 捕捉列表 3. lambda底层原理 1. C98对自定义类型的排序 在C98中&#xff0c;想要对自定义类型就行排序&#xff0c;我们得自己写仿函数来表明我们相对哪一项进行排序 struct Student {Student(string name, long id…

计算机算法分析与设计(16)---Dijkstra算法(含C++代码)

文章目录 一、知识概述1.1 算法描述1.2 例题分析 二、代码编写 一、知识概述 1.1 算法描述 1.2 例题分析 二、代码编写 输入&#xff1a;  第一行&#xff1a;图的顶点数n  第二行&#xff1a;图的边数k  第三行&#xff1a;算法起点begin&#xff0c;算法终点end  接下来…

物联网AI MicroPython传感器学习 之 RTC时钟模块

学物联网&#xff0c;来万物简单IoT物联网&#xff01;&#xff01; 一、产品简介 DS1302 是DALLAS 公司推出的涓流充电时钟芯片&#xff0c;内含有一个实时时钟/日历和31字节静态RAM&#xff0c;实时时钟/日历电路提供秒、分、时、日、周、月、年的信息&#xff0c;每月的天数…

Tomcat启动控制台乱码问题

修改Tomcat/conf/logging.properties

微信小程序中如何使用fontawesome6的免费图标

一、官网下载fontawesome6 Download Font Awesome Free or Pro | Font Awesome 二、使用transfer编码成Base64 transfer打开官网&#xff1a;Online font-face generator — Transfonter 首先先把刚刚下载的fontawesome6解压&#xff0c;将文件夹中的字体上传&#xff08;点…

【MATLAB第80期】基于MATLAB的结构核岭回归SKRR多输入单输出回归预测及分类预测模型

【MATLAB第80期】基于MATLAB的结构核岭回归SKRR多输入单输出回归预测及分类预测模型 SKRR这是Gustau Camps-Valls等人在“用深度结构核回归检索物理参数”中提出的结构核岭回归&#xff08;SKRR&#xff09;方法。 参考文献&#xff1a; Camps-Valls,Retrieval of Physical Pa…

[C++] C++入门

☃️个人主页&#xff1a;fighting小泽 &#x1f338;作者简介&#xff1a;目前正在学习C和Linux &#x1f33c;博客专栏&#xff1a;C入门 &#x1f3f5;️欢迎关注&#xff1a;评论&#x1f44a;&#x1f3fb;点赞&#x1f44d;&#x1f3fb;留言&#x1f4aa;&#x1f3fb; …

JUC并发编程笔记2

省流&#xff1a; 自己笔记&#xff0c;划走~~~~ 缓存更新策略

【数据科学赛】2023全球智能汽车AI挑战赛 #¥95000 #LLM文档问答 #视频理解

CompHub[1] 最新的比赛会第一时间在群里通知&#xff0c;欢迎加群交流比赛经验&#xff01;&#xff08;公众号回复“加群”即可&#xff09; 以下内容由AI辅助生成&#xff0c;可能存在错误&#xff0c;可进入比赛主页[2]查看更多(文末阅读原文) 比赛主办方 吉利汽车集团、阿…

2008-2021年上市公司实体企业金融化程度测算数据(原始数据+stata代码)

2008-2021年上市公司实体企业金融化程度测算&#xff08;原始数据stata代码&#xff09; 1、时间&#xff1a;2008-2021年 2、指标&#xff1a;股票代码、年份、交易性金融资产、衍生金融资产、发放贷款及垫款净额、可供出售金融资产净额、持有至到期投资净额、长期债权投资净…

Golang数组:全面指南与实际示例

揭示Golang数组的威力&#xff1a;从基础到高级技巧 Golang数组是数据存储的基本构建块&#xff0c;为开发人员提供了多种可能性。在这篇正式的博客文章中&#xff0c;我们将探讨Golang数组&#xff0c;从基础知识到高级技巧。通过实际示例和正式的语气&#xff0c;我们将揭示…

react 学习 —— 16、使用 ref 操作 DOM

什么时候使用 ref 操作 DOM&#xff1f; 有时你可能需要访问由 React 管理的 DOM 元素 —— 例如&#xff0c;让一个节点获得焦点、滚动到它或测量它的尺寸和位置。在 React 中没有内置的方法来做这些事情&#xff0c;所以你需要一个指向 DOM 节点的 ref 来实现。 怎么使用 r…

vue3实现在element Dialog 对话框中预览pdf文件

最近有一个需求就是点击按钮在弹框中去预览pdf文件&#xff0c;于是发现了一个HTML中比较重要的标签&#xff1a;embed&#xff0c;前面说的需求就可以用这个标签来实现&#xff0c;一起来学习一下吧。 embed标签是HTML中的一个非常重要的标签&#xff0c;它可以在你的网页上插…

PDF编辑阅读 PDF Expert v3.5.2

PDF Expert是由Readdle开发的一款专业的PDF编辑和阅读工具。它可以帮助用户在Mac、iPad和iPhone等设备上查看、注释、编辑、填写和签署PDF文档。 以下是PDF Expert的特点&#xff1a; PDF编辑&#xff1a;PDF Expert提供了丰富的PDF编辑功能&#xff0c;包括添加、删除、移动…