網(wǎng)站建設(shè)華網(wǎng)天下公司搜索引擎內(nèi)部?jī)?yōu)化
項(xiàng)目場(chǎng)景:
前端使用vue3+ts 后端使用nestjs
1.申請(qǐng)appId,appKey
1.進(jìn)入qq互聯(lián)官網(wǎng)。創(chuàng)建應(yīng)用
特別注意
1.在填寫網(wǎng)站回調(diào)域時(shí),需要你線上真實(shí)能訪問(wèn)的。不然審核不通過(guò)。我的回調(diào)地址是前端路由地址
2.如果你想本地調(diào)試,回調(diào)到你的線上地址。你可以在本地設(shè)置本地域名,做反向代理。我是用的是phpstudy,方向代理自己的線上域名。
如果你還是不明白,可以留言
2.代碼演示
特別注意:
如果你跟我一樣是前后端分離的模式開(kāi)發(fā)的,應(yīng)用回調(diào)地址填寫的應(yīng)該是你的前端路由地址。在你的前端頁(yè)面獲取code,把code值傳給后端接口。后端接口通過(guò)code獲取gitee用戶信息。
代碼演示
我的應(yīng)用回調(diào)地址:http://localhost:8080/vuecms/qq
- 前端點(diǎn)擊qq圖標(biāo)登錄代碼:
<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 = 你的回調(diào)地址;const state = Date.now()let scope = "get_user_info,list_album"return qqOauthConfig.authorizeUrl+`&client_id=${appId}&redirect_uri=${redirectUrl}&state=${state}&scope=${scope}`;}
- 回調(diào)地址前端代碼
<template><div class="u-f u-f-ac u-f-ajc" style="width: 100%;height:100vh"><template v-if="isOauth"><el-resulticon="success"title="授權(quán)成功,跳轉(zhuǎn)中..."></el-result></template><template v-else><el-resulticon="error"title="授權(quán)失敗"></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,通過(guò)code對(duì)后端發(fā)起請(qǐng)求,獲取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請(qǐng)求的后端代碼
// qq 的認(rèn)證配置
export const qqOauthConfig = {cid: "",//gitee官網(wǎng)設(shè)置獲取secret: "",redirectURL: '',//gitee官網(wǎng)配置進(jìn)行填寫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過(guò)期,請(qǐng)重新登錄")}let giteeInfo:any = await this.getQQInfoByAccessToken(accessToken.data.accessToken,accessToken.data.appId);if(!giteeInfo.data){return this.msgService.fail("獲取qq賬號(hào)信息失敗")}let { nickname } = giteeInfo.data.userData;let clientId = 0;let qqId = sysConfigEnum.qqLoginConfig + JSON.parse(JSON.stringify(giteeInfo.data.openid));//判斷qq是否有關(guān)聯(lián)賬號(hào)。如果有就登陸,沒(méi)有就新創(chuàng)建一個(gè)賬號(hào)let userNum = await this.userEntity.createQueryBuilder().where({ qqId:qqId }).getCount()let username;//沒(méi)有賬號(hào),注冊(cè)帳號(hào)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;//回調(diào)路勁獲取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},"");}}//通過(guò)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.特別注意
如果以上步驟都沒(méi)問(wèn)題。需要把本地測(cè)試回調(diào)地址改為線上路徑
如果你還是不懂,你可以克隆下我的項(xiàng)目。開(kāi)源免費(fèi)。如果對(duì)你有幫助,給我一個(gè)star就行了
https://gitee.com/derekgo/vue-cms_xg
? 踩坑不易,還希望各位大佬支持一下 \textcolor{gray}{踩坑不易,還希望各位大佬支持一下} 踩坑不易,還希望各位大佬支持一下
📃 個(gè)人主頁(yè): \textcolor{green}{個(gè)人主頁(yè):} 個(gè)人主頁(yè): 沉默小管
📃 個(gè)人網(wǎng)站: \textcolor{green}{個(gè)人網(wǎng)站:} 個(gè)人網(wǎng)站: 沉默小管
📃 個(gè)人導(dǎo)航網(wǎng)站: \textcolor{green}{個(gè)人導(dǎo)航網(wǎng)站:} 個(gè)人導(dǎo)航網(wǎng)站: 沉默小管導(dǎo)航網(wǎng)
📃 我的開(kāi)源項(xiàng)目: \textcolor{green}{我的開(kāi)源項(xiàng)目:} 我的開(kāi)源項(xiàng)目: vueCms.cn
🔥 技術(shù)交流 Q Q 群: 837051545 \textcolor{green}{技術(shù)交流QQ群:837051545} 技術(shù)交流QQ群:837051545
👍 點(diǎn)贊,你的認(rèn)可是我創(chuàng)作的動(dòng)力! \textcolor{green}{點(diǎn)贊,你的認(rèn)可是我創(chuàng)作的動(dòng)力!} 點(diǎn)贊,你的認(rèn)可是我創(chuàng)作的動(dòng)力!
?? 收藏,你的青睞是我努力的方向! \textcolor{green}{收藏,你的青睞是我努力的方向!} 收藏,你的青睞是我努力的方向!
?? 評(píng)論,你的意見(jiàn)是我進(jìn)步的財(cái)富! \textcolor{green}{評(píng)論,你的意見(jiàn)是我進(jìn)步的財(cái)富!} 評(píng)論,你的意見(jiàn)是我進(jìn)步的財(cái)富!
如果有不懂可以留言,我看到了應(yīng)該會(huì)回復(fù)
如有錯(cuò)誤,請(qǐng)多多指教