前言
實習過程中,我參與了web版相冊管家的開發,負責登陸頁面的前后端邏輯。
需要在登陸頁接入QQ互聯和微信掃碼登陸,而且是用頁面內嵌方式。回頭來看其實兩者都有文檔指導,步驟清楚,並不復雜。但是第一次接觸難免踩坑,在此梳理如下,方便今后開發參考。
QQ互聯
應用申請
申請appid和appkey
-
appid:應用的唯一標識。在OAuth2.0認證過程中,appid的值即為oauth_consumer_key的值。
-
appkey:appid對應的密鑰,訪問用戶資源時用來驗證應用的合法性。在OAuth2.0認證過程中,appkey的值即為oauth_consumer_secret的值。
-
tip: 申請時注意網站回調域必須為網站地址下的子目錄,用戶授權后頁面會跳轉到這個回調地址,通常情況下我們需要取得該地址的code參數進行后續接入流程,所以要保證該地址中的代碼可控。
授權登陸流程
-
qq互聯的授權流程如下圖所示:
-
本文中列出的是server-side模式的登陸流程,client-side模式可參考 https://wiki.connect.qq.com/開發攻略_client-side
Step 1 獲取Authorization Code
- 瀏覽器訪問授權頁地址:https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=[YOUR_APPID]&redirect_uri=[YOUR_REDIRECT_URI]&scope=[THE_SCOPE]
- 參數列表如下,把client_id、redirect_uri、scope按照列表修改
tip:redirect_uri必須與注冊應用的時候填的回調域一樣,該項在申請通過后可以在qq互聯應用管理處修改,無需再次審核。
-
參數正確后,該鏈接會顯示QQ授權頁,會自動檢測PC端以及手機端登陸過的qq賬號,並給出登陸選項
-
授權頁登錄后,瀏覽器會自動跳轉到回調地址,帶上code參數,例如
http://localhost:3000/proxy?code=D21B82BA835586D8DF86135675EC71BD
此時,從url中取得code,進行下一步。
tip:該code會在10分鍾內過期,且無法重復使用
Step 2 通過Authorization Code獲取Access Token
-
請求方法:GET
-
如果請求成功,返回值的body里面會包括access_token=FE04*CCE2&expires_in=7776000&refresh_token=88E4*BE14,可從中取得access_token
-
tip 1: 返回值為字符串,不是json對象,需要自己拆分
-
tip 2: 參數中的redirect_uri在此並不涉及跳轉,只做驗證
-
tip 3: 若想實現權限自動續期,參考 https://wiki.connect.qq.com/使用authorization_code獲取access_token#Step2.EF.BC.9A.E9.80.9A.E8.BF.87AuthorizationCode.E8.8E.B7.E5.8F.96AccessToken
Step 3 使用Access Token 獲取用戶openid/unionid
- 請求地址: https://graph.qq.com/oauth2.0/me?access_token=ACCESSTOKEN&unionid=1
- 請求方法:GET
- 請求參數: 上一步獲取的 access_token(必需)unionid(非必需),標識是否申請unionID
- 請求成功返回值:
callback( {"client_id":"YOUR_APPID","openid":"YOUR_OPENID","unionid":"YOUR_UNIONID"} );
- tip: 返回值為一個帶callback的字符串,非對象,需要自己拆分。
Step 4 使用用戶OpenID獲取用戶信息
-
使用access_token, appid, openid調用get_user_info接口,可獲取用戶信息。
iframe 內嵌登陸框實現
UI要求實現的是類似於微雲一樣的內嵌登陸框效果
我找了一圈,沒發現qq互聯有可以自定義生成登陸界面或者登陸二維碼的操作(微信有),參考了幾個內嵌登陸的網站,發現大家的UI和大小都是固定的,猜想應該是通過iframe截取實現的,官方給的demo也是類似思路。
於是我自己琢磨着用iframe截取授權登陸頁面,然后通過iframe向父頁面傳值拿到code。怎么想這么搞都挺笨的,奈何沒找到更簡單的方法,拋磚引玉,如果有更方便的思路麻煩告知。
內嵌iframe,局部定位
- iframe局部定位有很多種方法,我這里采取的是用多個div來截取的方式,調整起來比較靈活,大家用自己喜歡的方式就行。
<div style="margin:0 auto;" v-if="isQQ">
<div style="width:360px;height:250px;overflow:hidden;border:0px;margin:0 auto; padding-top:30px;">
<div style="width:500px;height:800px;margin:-103px 0px 0px -95px;">
<iframe id="qq_login_frame" :src="iframeSrc" width="800" height="600" scrolling="no">
</iframe>
</div>
</div>
</div>
截出來的效果如下:
- tips: 截取時的范圍需要考慮鼠標懸停時會浮現的提示框,以及掃碼后的提示界面文字的范圍,不只是圖標范圍,截取太小會導致被遮擋。
父子頁面傳值,獲取code
- 在登陸授權后,iframe內會跳轉到帶着code參數的,我們申請的回調頁面。在該回調頁面內,從url中取得code,並傳給父頁面,即我們的登陸頁面。
- vue框架下的代碼如下,思路都差不多
mounted() {
let codeUrl = window.location.href;
let code = this.getCode(codeUrl)
this.sendLoginCode(code)
},
methods: {
// 拆分url獲取code
getCode(url) {
if (url.indexOf('code') !== -1) {
let params = url.split('?')[1].split('&')[0].split('=')[1];
return (params);
}
},
// 發送給父頁面
sendLoginCode(code) {
window.parent.postMessage({
type: "sendCode",
data: code
}, '*');
},
}
- 在父頁面對iframe的傳值進行監聽,拿到code之后就一切好說,按照前述流程去后端獲取用戶信息就好了
// 監聽iframe的返回 window.addEventListener('message', (e) => { console.log(e,e.data) let data = e.data; if(data && data.type && data.type == 'sendCode') { let code = data.data; this.getUserInfo(code) } }, false);
微信掃碼登陸
應用申請
- 在微信開放平台進行應用申請,與qq互聯的應用申請相似
- tip:注意!!! 微信應用的回調域和qq互聯的不同,舉個例子,你的網站是http://a.com, qq互聯的回調域只能是你申請時填寫的http://a.com/login。但是,微信申請時的授權回調域填寫你的主域名即可,因為
如果你申請微信的回調域也填寫http://a.com/login,在生成授權頁面時redirect_uri使用http://a.com/login會報錯,並不能生成授權頁面。
授權登陸流程
- 微信的授權登陸流程與QQ互聯基本相同,區別在於code以及access_token的有效期,以及code可以直接換取access_token+openid,在此不再贅述,具體流程和接口可參考開發文檔,以及接口文檔 https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419316518&lang=zh_CN
內嵌二維碼
JS實現以及樣式調整
- 微信為前端提供了直接可以通過JS實現二維碼生成的方法(感謝微信!!)
- 先在頁面中引入js文件(支持https)
http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js
- 在需要使用微信登陸的地方實例化以下JS對象
var obj = new WxLogin({
self_redirect:true,
id:"login_container",
appid: "",
scope: "",
redirect_uri: "",
state: "",
style: "",
href: ""
});
參數列表如下:
- 這里的href參數可以自定義掃碼樣式,一種據說是引入一個https地址的css文件例如:href: "https://lws.com/test.css",由於沒有配置https所以沒有實踐,另一種是把樣式代碼進行base64加密放到href參數中。
- 微信提供的樣式代碼如下
.impowerBox .qrcode {width: 200px;}
.impowerBox .title {display: none;}
.impowerBox .info {width: 200px;}
.status_icon {display: none}
.impowerBox .status {text-align: center;}
按照自己的需求修改調整后,將樣式代碼轉為base64加密,放入代碼,這里我用的站長工具,大家自由發揮。
- 然后將用如下href實例化JS對象就可以了,二維碼大小即可自由調整~
href:"data:text/css;base64,[加密后的樣式代碼]"
code拿取
- 其實微信js對象生成的二維碼,也是個iframe,掃碼后還是會跳轉到你傳入的回調地址,由於url形式和qq互聯相同,我這里和qq互聯使用的是相同的回調地址,采用和qq互聯相同的方式即可取到code。