第三方登陸/微信登陸/微信webview登陸/微信短信授權(quán)登陸?
時(shí)間:2023-11-14 08:18:01 | 來(lái)源:網(wǎng)站運(yùn)營(yíng)
時(shí)間:2023-11-14 08:18:01 來(lái)源:網(wǎng)站運(yùn)營(yíng)
第三方登陸/微信登陸/微信webview登陸/微信短信授權(quán)登陸?:
簡(jiǎn)介詳細(xì)討論如何通過(guò)迭代演進(jìn),最終實(shí)現(xiàn)一個(gè)以微信小程序作為認(rèn)證媒介的 OAuth 2 驗(yàn)證流程,在保證安全的前提下,為網(wǎng)頁(yè)提供獲取系統(tǒng)用戶信息的能力。
本文最終探討了如何將微信小程序作為系統(tǒng)的 OAuth 認(rèn)證媒介,而不是講述如何在微信小程序中對(duì)接微信登錄。
前提整篇討論都限于通過(guò)企業(yè)認(rèn)證的微信小程序,個(gè)人版的微信小程序不適用!
企業(yè)的微信小程序和微信的對(duì)接已經(jīng)完成。
背景企業(yè)基于微信小程序開(kāi)發(fā)了完整的登錄注冊(cè)、用戶檔案等功能。隨后,企業(yè)的運(yùn)營(yíng)方不斷地在營(yíng)銷(xiāo)活動(dòng)中復(fù)用微信小程序的登錄注冊(cè)和用戶信息獲取的能力,這種營(yíng)銷(xiāo)活動(dòng)頁(yè)面,通常外包給第三方開(kāi)發(fā),以 webview 的形式嵌入在微信小程序中,本質(zhì)上是一個(gè) html 網(wǎng)頁(yè)。
復(fù)用價(jià)值節(jié)省開(kāi)發(fā)成本這種活動(dòng)頁(yè)面成百上千,由不同的外包服務(wù)商獨(dú)立開(kāi)發(fā),每次都要獨(dú)立開(kāi)發(fā)登錄注冊(cè)的話,成本太大。從 DRY 原則上說(shuō),這些活動(dòng)頁(yè)面只需要關(guān)注每次活動(dòng)的具體變化的內(nèi)容即可(通常是一個(gè)不同的網(wǎng)頁(yè)小游戲)。
提升用戶體驗(yàn)登錄注冊(cè)時(shí),要求用戶提供手機(jī)號(hào),這十分普遍。但是,在網(wǎng)頁(yè)中實(shí)現(xiàn)這個(gè)功能,一般都是通過(guò)用戶填寫(xiě)手機(jī)號(hào),接收驗(yàn)證碼,再填入驗(yàn)證碼由服務(wù)器驗(yàn)證。這個(gè)過(guò)程比較耗時(shí),需要用戶的多次輸入。相反,微信小程序可以利用微信的能力,只需要用戶點(diǎn)擊一次授權(quán)按鈕,即可獲得手機(jī)號(hào)。
通過(guò)重用微信小程序的用戶登錄注冊(cè)功能,用戶感受更方便快捷。
需求分析這些活動(dòng)頁(yè)面,最終需要的用戶信息,多數(shù)情況下,只有一個(gè),那就是用戶在系統(tǒng)中的唯一標(biāo)識(shí)。這樣,在隨后的互動(dòng)中,就可以區(qū)分不同的用戶來(lái)。比如,在游戲互動(dòng)中,用戶中獎(jiǎng)了,就需要記錄是誰(shuí)中了什么獎(jiǎng)。因?yàn)檫@些互動(dòng)方式都是第三方開(kāi)發(fā)的,由他們來(lái)存儲(chǔ)這些中獎(jiǎng)信息很自然。但最終要關(guān)聯(lián)到內(nèi)部系統(tǒng)的用戶,就需要這個(gè)用戶身份標(biāo)識(shí)。
所以,終極問(wèn)題是,
微信小程序的 webview 里的網(wǎng)頁(yè),如何獲取到微信小程序的用戶唯一身份標(biāo)識(shí)?方案零(客戶端明文傳輸用戶身份標(biāo)識(shí),可以立即否決)在 webview 里的互動(dòng)進(jìn)行到某個(gè)時(shí)機(jī),網(wǎng)頁(yè)調(diào)起微信小程序的登錄注冊(cè)功能,用戶完成登錄注冊(cè)之后,微信小程序通過(guò) url 回調(diào)網(wǎng)頁(yè),在 query string 中,帶上 userId。
安全性不安全!
開(kāi)發(fā)周期最短
修改范圍- 微信小程序客戶端,回調(diào)網(wǎng)頁(yè) url 功能
- 網(wǎng)頁(yè)端,接收回調(diào)并讀取 userId 參數(shù)的功能
解決了什么?webview 中的網(wǎng)頁(yè)獲取不到 userId 的問(wèn)題
不能解決什么?沒(méi)有安全性可言。如果通過(guò)偽造 userId 直接調(diào)用網(wǎng)頁(yè)的 url,在該網(wǎng)頁(yè)的域中,用戶身份信息就被偽造了。
補(bǔ)救措施一旦發(fā)現(xiàn)這種行為,網(wǎng)頁(yè)端能做的是改版,不展示任何用戶信息;但是數(shù)據(jù)庫(kù)里存放的錯(cuò)誤映射關(guān)系,沒(méi)有辦法恢復(fù)了,不能再被使用。
流程結(jié)論不能使用!
方案一(jwt,不推薦)由于前端 url 的傳遞參數(shù)容易修改,所以需要避開(kāi)使用前端在不同系統(tǒng)間直接明文傳遞 userId 的方式。一個(gè)很自然的想法就是使用 jwt,將 userId 包裝在 jwt 里,由小程序傳給 webview。網(wǎng)頁(yè)端接收到 jwt 后,需要驗(yàn)證 jwt 是否有效。由于 jwt 一旦被篡改,就通不過(guò)校驗(yàn),從而可以防止任意偽造 userId 的情況。
安全性較不安全
開(kāi)發(fā)周期很短
修改范圍- 微信小程序前端,直接傳遞小程序后端的 jwt 給到 webview
- 網(wǎng)頁(yè)端后端,驗(yàn)證 jwt
解決了什么方案零的安全問(wèn)題。在方案零中,任何人都可以通過(guò)猜測(cè) userId,遍歷所有網(wǎng)頁(yè)端保存過(guò)的用戶信息。采用這個(gè)方案,猜測(cè)的 userId 會(huì)通不過(guò)網(wǎng)頁(yè)端后端的驗(yàn)證。
不能解決什么被捕獲的 jwt,在有效期內(nèi),可以被重放攻擊。用戶 Bob 仍然可以通過(guò)拿到用戶 Alice 的 jwt,打開(kāi)網(wǎng)頁(yè) url,看到 Alice 的信息。
補(bǔ)救措施同方案零
流程前提這個(gè)方案由于使用了 jwt,并且要求網(wǎng)頁(yè)服務(wù)器端做驗(yàn)證,所以需要微信小程序后端和網(wǎng)頁(yè)后端共享頒發(fā) jwt 的密鑰。
結(jié)論不推薦!
因?yàn)楹茈y把控第三方開(kāi)發(fā)們,一定做了驗(yàn)證操作。而且,要共享密鑰,這不可行。
方案二(OAuth 2 客戶端憑據(jù)許可模式)由于方案零和方案一,本質(zhì)上都是通過(guò)客戶端傳遞 userId,只是一個(gè)通過(guò)明文,一個(gè)通過(guò) jwt。綜上所述,這都不安全,所以可以再進(jìn)一步,去掉客戶端交流用戶信息的渠道,而改為服務(wù)器端來(lái)進(jìn)行 userId 的查詢。即讓網(wǎng)頁(yè)端的服務(wù)器端來(lái)向小程序服務(wù)器端查詢 userId,但這要求網(wǎng)頁(yè)服務(wù)器端在查詢時(shí)帶上用戶的另一信息??紤]到都是在微信生態(tài),可以讓網(wǎng)頁(yè)服務(wù)器端查詢系統(tǒng)的 userId 時(shí),帶上unionId。
安全性較安全
開(kāi)發(fā)同期較短
修改范圍- 微信小程序后端,OAuth 2 client_credential 授權(quán)功能;以及改造原有微信小程序的登錄注冊(cè)流程,在原有的登錄注冊(cè)流程之后,保存一下 unionId, userId 的映射關(guān)系,并對(duì)受信任的客戶端(對(duì)微信小程序后端是客戶端,但實(shí)現(xiàn)上通常是服務(wù)器端)開(kāi)放查詢接口。
- 網(wǎng)頁(yè)后端,這個(gè)方案需要服務(wù)器和服務(wù)器間的溝通;另外網(wǎng)頁(yè)后端要對(duì)接微信服務(wù),實(shí)現(xiàn) unionid 的獲取功能
解決了什么由于 url 上不用帶上明文或者加密的 userId,用戶 Bob 沒(méi)有機(jī)會(huì)偽造用戶 Alice 的身份,更不能通過(guò)猜測(cè) userId 遍歷系統(tǒng)用戶了。
不能解決什么一旦網(wǎng)頁(yè)端服務(wù)器獲取到了服務(wù)器端信任的令牌,就可以從微信小程序后端查詢?nèi)我庥脩舻?userId(不需要用戶授權(quán))。所以這個(gè)方案并不能防止網(wǎng)頁(yè)端服務(wù)器來(lái)遍歷會(huì)員信息。
補(bǔ)救措施一旦發(fā)現(xiàn)網(wǎng)頁(yè)端本身存在不安全的行為,可以立即吊銷(xiāo)用于建立服務(wù)器端信任的 client id 和 secret,使得網(wǎng)頁(yè)端服務(wù)器不能再使用 userId 的查詢接口。
流程- 網(wǎng)頁(yè)授權(quán)拿到了用戶的 unionId
- 網(wǎng)頁(yè)服務(wù)器端用 unionId,向小程序服務(wù)器查詢userId (server to server talk 的方式)
- 查到直接做后續(xù)操作
- 沒(méi)查到拉起小程序登錄注冊(cè),然后小程序回調(diào)網(wǎng)頁(yè)(webview 方式)
- 網(wǎng)頁(yè)的邏輯回到 2,再次查詢。得到 userId,進(jìn)行后續(xù)操作
前提網(wǎng)頁(yè)端使用和小程序在相同的開(kāi)發(fā)平臺(tái)里綁定到同一公眾號(hào)主體的賬號(hào),授權(quán)獲取 unionid。
結(jié)論在工期緊急的情況下,推薦使用
方案三(OAuth 2 授權(quán)碼許可模式)方案二要求系統(tǒng)信任網(wǎng)頁(yè)端,從而開(kāi)放 userId 查詢權(quán)限給到網(wǎng)頁(yè)端。注意當(dāng)把用戶的 userId 給到網(wǎng)頁(yè)端時(shí),不需要經(jīng)過(guò)用戶的同意,因?yàn)椴捎昧丝蛻舳藨{據(jù)許可模式。
本方案更進(jìn)一步,網(wǎng)頁(yè)端要獲取用戶的 userId,需要經(jīng)過(guò)用戶顯式同意,即采用 OAuth 2 的授權(quán)碼許可模式。
安全性更安全
開(kāi)發(fā)周期最長(zhǎng)
修改范圍- 微信小程序后端采用 OAuth 2 的授權(quán)碼許可模式
- 微信小程序前端增加用戶授權(quán)第三方查看其信息的頁(yè)面
- 網(wǎng)頁(yè)端服務(wù)器對(duì)接 OAuth 2 的流程
解決了什么這個(gè)方案解決了方案二不能防止網(wǎng)頁(yè)端遍歷系統(tǒng)用戶的問(wèn)題,因?yàn)橹挥杏脩麸@式授權(quán),它才能拿到用戶信息。
不能解決什么一旦用戶同意,userId 就“泄露”給了網(wǎng)頁(yè)端。這個(gè)網(wǎng)頁(yè)應(yīng)用自己保存的(userId, 中獎(jiǎng)信息)這個(gè)映射關(guān)系,由這個(gè)網(wǎng)頁(yè)應(yīng)用自己負(fù)責(zé)保證安全。
補(bǔ)救措施如果發(fā)現(xiàn)網(wǎng)頁(yè)端應(yīng)用本身存在不安全的行為,可以吊銷(xiāo)其 clientid/secret,使得該網(wǎng)頁(yè)端不能再訪問(wèn)微信小程序后端接口。
流程1. 網(wǎng)頁(yè)端的已有流程(方案二中的網(wǎng)頁(yè)端要求用戶授權(quán),拿用戶的 unionid,這一步可以去掉)
2. 網(wǎng)頁(yè)端拉起小程序,用戶登錄/注冊(cè)和小程序自己內(nèi)部的登錄/注冊(cè)要多一步,即展示一個(gè)頁(yè)面,明確告知用戶:該網(wǎng)頁(yè)應(yīng)用想使用你的憑據(jù),以獲取你的用戶信息。措詞可以相應(yīng)修改
3. 用戶拒絕登錄/注冊(cè),流程結(jié)束
4. 用戶如果同意,在小程序完成了登錄注冊(cè)流程,那么小程序回調(diào)webview,在 url query string 里帶上一個(gè)后端頒發(fā)的臨時(shí) code,有效期 5 分鐘(防止重放,有效期必須很短,而且限制只能被使用一次)
5. 網(wǎng)頁(yè)端服務(wù)器向小程序后端請(qǐng)求授權(quán)(client_credential)
6. 授權(quán)失敗,流程結(jié)束
7. 授權(quán)成功,使用server trust access_token 作為憑據(jù),用 code 換取用戶的 access_token,scope: userinfo
8. 換取失敗,流程結(jié)束
9. 換取成功,使用該用戶 access_token,向小程序后端查詢用戶信息(userId 等等)
結(jié)論在時(shí)間允許的情況下,最推薦使用這個(gè)方案!
總結(jié)本文列舉了在webview中復(fù)用微信小程序的登錄注冊(cè)功能以換取用戶信息的 4 種方案,今天就寫(xiě)到這里。如果有考慮不周的地方,后面再發(fā)文修補(bǔ),再有時(shí)間甚至可以分享關(guān)鍵代碼,或者做一個(gè)開(kāi)源代碼庫(kù)。