讓 Discuz X2.5 在 http 協定下透過 https 協定進行登入動作

前幾天才嘗試修改讓 Discuz! X2.5 可以支援 https 協定 下運作
昨天登入 Google 的 Search Console 收到這樣的提示

自 2017 年 1 月起,Chrome (56 以上版本) 會將收集密碼或信用卡詳細資料的網頁標示為「不安全」(透過 HTTPS 提供的網頁除外)。

下列網址包含密碼或信用卡詳細資料的輸入欄位,將會觸發這項新的Chrome 警告。請查看這些示例,掌握這類警告出現的位置,方便您採取有助於保護使用者資料的行動。請注意,這份清單中僅列出部分示例。

目前鸚鵡裝的是 Chrome 55 版,在 http 協定連線時,網址列前面是一個圓形驚嘆號
但不會有其他提示,不知道 Chrome 56 會不會跳出提示
為了避免被跳出不安全的提示,所以決定再來嘗試改一下程式碼
讓論壇即使是 http 協定連入,登入表單也必定傳送到 https 協定

跟登入有關的樣板檔案有兩個
一個是論壇右上角的快速登入表單 (login_simple.htm)
另一個是浮動視窗的登入表單 (login.htm)
將兩個樣板檔案中 form 的 action 修改成 https 的網址,登入時會發生錯誤

再追一下 Discuz 的登入實作方式和流程
流程是 form 的 target 是指向一個隱藏 iframe (即時建立)
再透過 iframe 的 onload event 觸發 function 來讀取 iframe 內的相關資料

所以在 http 協定下將登入時的 form 對象改為 https 時
會造成讀取 iframe 內的 DOM 時違反了瀏覽器的 同源政策(Same-origin policy)

所以想到的就是得克服 同源政策 的限制

  1. 使用 iframe 且 FQDN 相同,但因 protocol 不同所以無法透過 document.domain 來解決
  2. 登入結果返回時,會有 xml 和 javascript code 兩種模式
    要透過 window.postMessage 來傳遞訊息就必修大量修改論壇程式
  3. 要以 JSONP 來解決也跟上面的情況一下,要大量修改
  4. 以 CORS (Cross-Origin Resource Sharing) 來實作可以解決
    但可能會有瀏覽器支援性的問題 (雖然現在要找到不支援的瀏覽器很難)

回頭看程式碼的時候在 source/class/class_member.php 中看到 第 3-8 行
登入處理時會先判斷 uid 是否存在,如果已經存在則直接顯示登入成功要顯示的資訊

 

原本鸚鵡決定的實作方式如下

  1. 讓 http 和 https 的 cookie 可以共用
  2. form 的 target 對象的 iframe 觸發 onload event 後
    若讀取 iframe 的 DOM 發生 cross-origin frame 錯誤時
    將 iframe 的 src 屬性設定為 form 的 action 屬性,且 protocol 改回使用 http
  3. iframe 重新載入時,https 登入時的 cookie 也會在 header 中一併送出
  4. class_member.php 確認 uid 之後直接返回登入結果
    這時候 iframe 的 onload event 觸發的 function 就可以正常讀取 iframe 內的 DOM

缺點是登入動作會多產生一次 Request,使用者體驗上登入動作會稍微慢一點點
測試起來好像沒有問題,可以正確登入,提示訊息也正常顯示
然後忽然想到登入失敗的部份,就測試一下
果然錯誤訊息沒辦法正常顯示….

那就… 改用 CORS 來實作吧,反正現在不支援的瀏覽器很難找  =..=

最後實作的方式是

  1. 讓 http 和 https 的 cookie 可以共用
  2. 在 https 協定下進行登入,使用原本的方式
    在 http 協定下進行登入,以 CORS 的方式來完成,並接受伺服器傳來的 cookie
  3. class_member.php 處理登入時如果檢查到 Origin 標頭
    就回應 Access-Control-Allow-Origin 相關 header
  4. XMLHttpRequest 取得回應的資料後,依循原本的處理模式進行處理

所以總共修改了6個檔案
樣板使用的是:default,有使用其他樣板就修改對應的檔案即可

  1. template/default/member/login.htm

     
  2. template/default/member/login_simple.htm

     
  3. static/js/common.js
    新增一個 function ajaxpostCors()

     
  4. static/js/logging.js
    ajaxpost 修改成 ajaxpostCors

     
  5. source/function/function_core.php
    搜尋 function dsetcookie ,然後修改成

     
  6. source/class/class_member.php
    搜尋 function on_login(),然後修改成

     

完成後進入 管理中心 -> 工具 -> 更新緩存,更新樣板緩存
讓瀏覽器可以載入新的 script 檔案,這樣就完成了