主要實現步驟
- 對接第三方平臺,獲取第三方平臺的用戶信息。
- 利用該用戶信息,完成本應用的注冊。
qq登錄接入
接入前的配置
登錄后,點擊頭像,進行開發者信息填寫,等待審核。
郵箱驗證后,等待審核。
審核通過后,然后就可以創建應用了。
然后填寫一些網站信息,等待審核。審核通過后,即可使用。
開始接入
1.導入qq登錄的sdk
<!-- QQ 登錄 -->
<script type="text/javascript" charset="utf-8" src="https://connect.qq.com/qc_jssdk.js" data-appid="您應用的appid"
data-redirecturi="qq掃碼后的回調地址(上面配置中可以查到)"></script>
2.點擊qq登錄,彈出掃碼窗口。
// QQ 登錄的 URL
const QQ_LOGIN_URL =
'https://graph.qq.com/oauth2.0/authorize?client_id=您的appid&response_type=token&scope=all&redirect_uri=您的掃碼后的回調地址'
window.open(
QQ_LOGIN_URL,
'oauth2Login_10609',
'height=525,width=585, toolbar=no, menubar=no, scrollbars=no, status=no, location=yes, resizable=yes'
)
3.掛起qq登錄。需要注意的是,掃碼登錄成功后,調試代碼需要在線上環境。
<span id="qqLoginBtn" v-show="false"></span>
// QQ 登錄掛起
onMounted(() => {
QC.Login(
{
btnId: 'qqLoginBtn' //插入按鈕的節點id
},
// 登錄成功之后的回調,但是需要注意,這個回調只會在《登錄回調頁面中被執行》
// 登錄存在緩存,登錄成功一次之后,下次進入會自動重新登錄(即:觸發該方法,所以我們應該在離開登錄頁面時,注銷登錄)
// data就是當前qq的詳細信息
(data, opts) => {
console.log('QQ登錄成功')
// 1. 注銷登錄,否則在后續登錄中會直接觸發該回調
QC.Login.signOut()
// 2. 獲取當前用戶唯一標識,作為判斷用戶是否已注冊的依據。(來決定是否跳轉到注冊頁面)
const accessToken = /access_token=((.*))&expires_in/.exec(
window.location.hash
)[1]
// 3. 拼接請求對象
const oauthObj = {
nickname: data.nickname,
figureurl_qq_2: data.figureurl_qq_2,
accessToken
}
// 4. 完成跨頁面傳輸 (需要將數據傳遞到項目頁面,而非qq登錄彈框頁面中進行操作)
brodacast.send(oauthObj)
// 針對于 移動端而言:通過移動端觸發 QQ 登錄會展示三個頁面,原頁面、QQ 吊起頁面、回調頁面。并且移動端一個頁面展示整屏內容,且無法直接通過 window.close() 關閉,所以在移動端中,我們需要在當前頁面繼續進行后續操作。
oauthLogin(LOGIN_TYPE_QQ, oauthObj)
// 5. 在 PC 端下,關閉第三方窗口
window.close()
}
)
})
4.跨頁面窗口通信
想要實現跨頁面信息傳輸,通常有兩種方式:
- BroadcastChannel:允許 同源 的不同瀏覽器窗口,Tab頁,frame或者 iframe 下的不同文檔之間相互通信。但是會存在兼容性問題。
- localStorage + window.onstorage:通過localStorage 進行 同源 的數據傳輸。用來處理 BroadcastChannel 不兼容的瀏覽器。
// brodacast.js
// 頻道名
const LOGIN_SUCCESS_CHANNEL = 'LOGIN_SUCCESS_CHANNEL'
// safari@15.3 不支持 BroadcastChannel,所以我們需要對其進行判定使用,在不支持 BroadcastChannel 的瀏覽器中,使用 localstorage
let broadcastChannel = null
if (window.BroadcastChannel) {
broadcastChannel = new BroadcastChannel(LOGIN_SUCCESS_CHANNEL)
}
/**
* 等待 QQ 登錄成功
* 因為 QQ 登錄會在一個新的窗口中進行,用戶掃碼登錄成功之后會回調《新窗口的 QC.Login 第二參數 cb》,而不會回調到原頁面。
* 所以我們需要在《新窗口中通知到原頁面》,所以就需要涉及到 JS 的跨頁面通訊,而跨頁面通訊指的主要就是《同源頁面的通訊》
* 同源頁面的通訊方式有很多,我們這里主要介紹:
* 1. BroadcastChannel -> https://developer.mozilla.org/zh-CN/docs/Web/API/BroadcastChannel
* 2. window.onstorage:注意:該事件不在導致數據變化的當前頁面觸發
*/
/**
* 等待回調,它將返回一個 promise,并攜帶對應的數據
*/
const wait = () => {
return new Promise((resolve, reject) => {
if (broadcastChannel) {
// 觸發 message 事件時的回調函數
broadcastChannel.onmessage = async (event) => {
// 改變 promise 狀態
resolve(event.data)
}
} else {
// 觸發 localStorage 的 setItem 事件時回調函數
window.onstorage = (e) => {
// 判斷當前的事件名
if (e.key === LOGIN_SUCCESS_CHANNEL) {
// 改變 promise 狀態
resolve(JSON.parse(e.newValue))
}
}
}
})
}
/**
* 發送消息。
* broadcastChannel:觸發 message
* localStorage:觸發 setItem
*/
const send = (data) => {
if (broadcastChannel) {
broadcastChannel.postMessage(data)
} else {
localStorage.setItem(LOGIN_SUCCESS_CHANNEL, JSON.stringify(data))
}
}
/**
* 清除
*/
const clear = () => {
if (broadcastChannel) {
broadcastChannel.close()
broadcastChannel = null
}
localStorage.removeItem(LOGIN_SUCCESS_CHANNEL)
}
export default {
wait,
send,
clear
}
5.拿到數據后,進行登錄(自己服務器登錄接口)操作。
- 傳入對應參數(loginType, accessToken)等參數進行用戶注冊判斷。
- 通過accessToken判斷用戶已經注冊,那么我們就直接在后臺查出用戶名和密碼直接登錄了。
- 通過accessToken判斷用戶未注冊,那么我們將跳轉到注冊頁面,讓其注冊。
// 打開視窗之后開始等待
brodacast.wait().then(async (oauthObj) => {
// 登錄成功,關閉通知
brodacast.clear()
// TODO: 執行登錄操作
oauthLogin("QQ", oauthObj)
})
// oauthLogin.js
import store from '@/store'
import router from '@/router'
import { message } from '@/libs'
import { LOGIN_TYPE_OAUTH_NO_REGISTER_CODE } from '@/constants'
/**
* 第三方登錄統一處理方法
* @param {*} oauthType 登錄方式
* @param {*} oauthData 第三方數據
*/
export const oauthLogin = async (oauthType, oauthData) => {
const code = await store.dispatch('user/login', {
loginType: oauthType,
...oauthData
})
// 返回 204 表示當前用戶未注冊,此時給用戶一個提示,走注冊頁面
if (code === LOGIN_TYPE_OAUTH_NO_REGISTER_CODE) {
message('success', `歡迎您 ${oauthData.nickname},請創建您的賬號`, 6000)
// 進入注冊頁面,同時攜帶當前的第三方數據和注冊標記
router.push({
path: '/register',
query: {
reqType: oauthType,
...oauthData
}
})
return
}
// 否則表示用戶已注冊,直接進入首頁
router.push('/')
}
微信掃碼登錄接入
登錄后,進行對應的應用注冊,填寫一大堆詳細信息,然后進行交錢,就可以使用微信登錄了。
開始接入
整個微信登錄流程與QQ登錄流程略有不同,分為以下幾步:
1.通過 微信登錄前置數據獲取 接口,獲取登錄數據(比如 APP ID)。就是后臺將一些敏感數據通過接口返回。
2.根據獲取到的數據,拼接得到 open url 地址。打開該地址,展示微信登錄二維碼。移動端微信掃碼確定登錄。
// 2. 根據獲取到的數據,拼接得到 `open url` 地址
window.open(
`https://open.weixin.qq.com/connect/qrconnect?appid=${appId}&redirect_uri=${redirectUri}&response_type=code&scope=${scope}&state=${state}#wechat_redirect`,
'',
'height=525,width=585, toolbar=no, menubar=no, scrollbars=no, status=no, location=yes, resizable=yes'
)
3.等待用戶掃碼后,從當前窗口中解析 window.location.search
得到用戶的 code
數據。 微信掃碼后,會重定向到登錄頁面。
/**
* 微信登錄成功之后的窗口數據解析
*/
if (window.location.search) {
const code = /code=((.*))&state/.exec(window.location.search)[1]
if (code) {
brodacast.send({
code
})
// 關閉回調網頁
window.close()
}
}
4.根據 appId、appSecret、code 通過接口獲取用戶的 access_token
5.根據 access_token 獲取用戶信息
6.通過用戶信息觸發 oauthLogin 方法。
調用的接口,都是后端通過微信提供的api來獲取到對應的數據,然后再通過接口返回給開發者。
// 等待掃碼登錄成功通知
brodacast.wait().then(async ({ code }) => {
console.log('微信掃碼登錄成功')
console.log(code)
// 微信登錄成功,關閉通知
brodacast.clear()
// 獲取 AccessToken 和 openid
const { access_token, openid } = await getWXLoginToken(
appId,
appSecret,
code
)
// 獲取登錄用戶信息
const { nickname, headimgurl } = await getWXLoginUserInfo(
access_token,
openid
)
console.log(nickname, headimgurl)
// 執行登錄操作
oauthLogin(LOGIN_TYPE_WX, {
openid,
nickname,
headimgurl
})
})
需要注意的是,在手機端,普通h5頁面是不能使用微信掃碼登錄的。
總結
相同點
- 接入前需要配置一些內容信息。
- 都需要在線上環境進行調試。
- 都是掃碼后在三方窗口中獲取對應的信息,發送到當前項目頁面進行請求,判斷用戶是否已經注冊,還是未注冊。已經注冊時,調用login接口時,password直接傳遞空字符串即可,后端可以通過唯一標識,獲取到對應的用戶名和密碼,直接返回token進行登錄。未注冊,就跳轉到注冊頁面,讓其注冊。
不同點
- qq接入需要導入qc_sdk。
- qq直接掃碼后即可獲取到用戶信息,就可以直接調用login接口進行判斷用戶是否注冊了。
- 微信掃碼后,獲取
code
來換取access_token, openid
,然后再通過access_token, openid
來換取用戶信息。然后再調用login接口進行判斷用戶是否注冊了。 - 作者:Spirited_Away