最近在研究 iqiyi 的登陸流程,發現他們的第三方登陸體驗挺好的。javascript
在目標頁面(如下目標頁面均指用戶當前瀏覽的頁面)點擊登陸,彈出登陸彈框,選擇第三方登陸,好比 qq,微信,點擊則新開頁面。php
在新頁面中登陸完畢,頁面會自動關閉,且剛剛那個頁面不刷新且自動進行狀態變動html
這個很簡單,經過 window.close()
便可實現java
可是問題是,第三方登陸頁通常不會本身在代碼中作這件事,畢竟通常登陸後是重定向到某個頁面(經過 ticket 寫入 cookie )而不是關閉當前頁面web
那麼如何關閉呢?其實也很簡單,讓目標頁面執行登陸頁的關閉便可安全
newWin = window.open("//open.weixin.qq.com")
// 在某個時機
newWin.close()
複製代碼
至於這個時機,就是登陸成功以後。微信
那麼目標頁面如何知道登陸成功了?websocket
你可能會想說能夠利用輪詢啊,長鏈接啊,再或者 websocket 咯cookie
這個是能夠實現,可是額外浪費了性能,其實在當前頁面(登陸完重定向的頁面)經過 window.opener
操做目標頁面dom
至於這東西是啥,你們應該都知道,不懂的看 MDN
因此這就要求,登陸完咱們最後重定向的頁面除了寫入 cookie 的做用,還有就是操做 window.opener
好比這是 iqiyi 第三方登陸後重定向的頁面 https://passport.iqiyi.com/oauth/closepage.php?fromurl=&from=29&isNew=0
其頁面代碼就是如下簡單的幾行
<html><head><script> //成功調用 document.domain="iqiyi.com"; window.opener.lib.__callbacks__._oAuthSuccess('http://passport.iqiyi.com/pages/user/success.action'); </script>
</head><body></body></html>
複製代碼
這裏須要將 domain 設爲一致,才能操做相同 domain 的 window
是的, www.iqiyi.com 的 domain 也被改成了 "iqiyi.com" 了,一樣的, iqiyi 的其餘子域名好比
https://edu.iqiyi.com/
等都改寫了 domain,使得全站都能順滑的實現無刷新登陸
最後看看代碼中的 window.opener.lib.__callbacks__._oAuthSuccess(xxx)
,其實做用也很簡單,一是關閉新開頁面,二是獲取用戶信息並更新狀態
這樣差很少就實現了咱們的需求,另外還有一點沒提到的是,寫入 cookie 的時候,domain iqiyi 寫的是二級域名 .iqiyi.com
,這樣其餘三級域名如 edu.iqiyi.com
才能共用 cookie
PS:在測試過程當中發現有 iqiyi 有兩個bug(截止 20/04/12),固然,普通用戶使用通常不會出現。。
除了全站須要改造 document.domain
外,正常來講是沒有問題,可是可能會遇到不能修改 domain 的場景,你要是問我有哪些場景,emmmm...反正我就是爲了說個人新方案的,新方案就是 postMessage
我如今能想到的一個,好比最後一個重定向的最後一個頁面不是
.iqiyi.com
域名,而是其餘頁面(多是爲了集團內多個產品複用吧),好比util.baidu.com
www.iqiyi.com
newWin = window.open("//util.baidu.com")
window.addEventListener("message",(evt)=>{
// 根據信息來源進行特殊處理,避免受其餘 postMessage 影響
if(evt.origin === "https://util.baidu.com"){
console.log(evt.data)
newWin.close()
// or
// evt.source.close()
}
})
複製代碼
util.baidu.com
window.opener.postMessage("test","*") //全部
複製代碼
能夠在 www.iqiyi.com 中看到輸出,且 util.baidu.com 自動關閉
固然該方案也有很差的地方,就是 postMessage 使用不當會致使安全問題,主要有如下2點
postMessage 第二個參數 targetOrigin 設置爲 * 可能致使數據泄露
好比使用了某個不安全的第三方登陸頁面,其對目標網站進行了重定向,好比變成 www.ihack.com
,第三方登陸後經過 postMessage 傳遞隱私信息,因爲設置的是 * ,致使 www.ihack.com
能夠收到隱私信息。固然你後面發現這個 ihack 網站不正常也沒用,由於數據已經泄露了。
解決方案就是 targetOrigin 設置爲特定的地址好比 edu.iqiyi.como
,這就須要咱們將當前頁面做爲傳遞到重定向頁面
舉例,像第三方登陸頁傳遞這樣的參數 -- &redirect_uri=https://passport.iqiyi.com?targetOrigin=edu.iqiyi.com
, 第三方登陸後重定向到 passport 寫入 cookie ,再次重定向到 https://util.baidu.com?targetOrigin=edu.iqiyi.com
,再當前頁面讀取 targetOrigin 參數並傳遞 postMessage 。整個就是這樣的一個過程
固然在本例中不須要傳遞隱私信息
接收 message 時請始終使用 origin 和 source 屬性驗證發件人的身份
好比點擊打開了用戶評論的 url(某個黑客網站),其對目標頁面發起 postMessage ,而咱們若是在收到 message 時不進行驗證就執行危險操做時,可能就會致使安全問題
另外,若是回調執行安全性依賴於消息的話(好比執行 eval(msg.data)
),即便檢查經過,還須要對消息格式再一次檢查,避免因信任網站收到跨站腳本攻擊而致使本網站也遭到攻擊 固然在本例中只是簡單的關閉新開頁面及發送請求,沒有什麼危險操做,檢查下 origin 便可
domain 適用於大部分情景,有全站改造 document.domain
的成本,且最後重定向頁面須要是相同的 domain
postMessage 適用於全部情景,對於安全問題須要額外處理
兩種方案各有千秋,看就具體的場景啦~