SSO (單點登錄)實現方式

jopen 10年前發布 | 169K 次閱讀 SSO OpenID/單點登錄SSO

SSO (Single-Sign-On) 即單點登錄,在互聯網應用中是多個站點通過一次登錄即可訪問所有產品,如Google所有產品通過 http://accounts.google.com/,百度所有產品統一登錄地點是 http://passport.baidu.com/ 等,也有些產品是提供自己的登錄界面,然后到統一入口驗證。總之,就是要實現一次登錄,處處登錄。

如果所有產品都是在同一主域下,那么只要把登錄的標識信息存放到主域的 cookie 中,即可實現訪問任一產品的頁面時把登錄信息傳遞到服務器,然后服務器根據該信息判斷是否需要用戶再次登錄。雖然大多數公司的產品都是在同一個域名下,但 有些還是獨立域名的,這時就涉及到跨域問題,也是 SSO 的難點所在。

基本思路是在一個固定的入口登錄,成功后返回一個 token,將這個 token 附帶在跨域訪問的某個文件上,該文件拿到這個 token 和服務器上存放的值比較,并獲取對應的登錄用戶信息,然后設置登錄標識 cookie,以此完成 SSO 登錄。服務器上的 token 可以存在 memcache 等緩存中,或者通過 RPC 訪問。

通過查看現有網站,主要是百度和新浪的 SSO 實現方案(截至2013-7-31),來對 SSO 實現方式有一個詳細的了解。

百度的 SSO

百度的很多產品都是在 baidu.com 這個主域名下,納入到 SSO 的其他獨立域名目前只有 hao123.com(很討厭這個網站,一不小心就會在裝軟件時將它設為默認首頁,還好現在不怎么用 IE)。

點擊百度產品的登錄,一般會跳轉到 passport.baidu.com,在這個頁面完成登錄,也有些是浮層,但登錄實現方式一樣:

  1. 填寫完用戶名密碼后,點擊“登錄”按鈕。

  2. js 創建一個 div 容器,在這個容器中主要創建兩個元素:form 表單和 iframe。

    </li>

    • from 中包含很多 type="hidden" 的 <input/> 標記,主要包含填寫內容和其他相關內容,如要登錄的產品標識和成功后的跳轉地址等。form 的提交目標窗口指向之后的 iframe。

    • iframe 初始地址所一個 _blank.html 文件,會造成一次 http 請求。

    • 這些內容都是拼成一個字符串,一次性寫入的。

    • </ul>

    • 動態創建節點完成后,馬上提交數據,指向 iframe 中 passport.baidu.com/v2/api/?login。

    • 提交返回的結果內容在 iframe 中,通過 js 中的 'location.replace()' 跳轉 iframe 到一個新的頁面,這個頁面是第2步中的表單項 'staticpage' 指定的,一般都叫 v3Jump.hmtl,不同產品只是路徑不同。

    • v3Jump.html 中的 js 的作用就是以形如 parent.someMethod({}) 的方式調用 iframe 父級窗口的 js 方法。涉及到不同域名調用主窗口 js 方法,因此一般 v3Jump.html 都是放在和主窗口同一域名下。

    • 主窗口的 js 處理頁面表現,同時為了實現跨域,會調用 https://user.hao123.com/static/crossdomain.php?bdu=...&t=3434312,這個 php 會根據 bdu 值驗證登錄狀態,并設置 hao123.com 這個域名的 cookie 登錄標識。比較巧妙的是,百度把這個地址作為一個 Image 對象的 src 屬性,這樣能完成請求,還不會渲染到頁面上。

    • 最后,主窗口的 js 跳轉頁面到指定的地址。

    • </ol>

      新浪的 SSO

      新浪的獨立域名好像只有一個 weibo.com,其他產品都是在 sina.com.cn 下。它的登錄方式與百度基本相同,這里挑選不同的幾點說明。

      在 weibo.com 登錄

      1. 同百度

      2. 同百度

      3. 提交數據到 iframe, 指向 login.sina.com.cn/sso/login.php,提交表單后,會立馬刪除 from 節點(百度只在登錄失敗再次提交時才替換這個 form 節點)

      4. 如果登錄失敗,iframe 中的內容為 location.replace() 跳轉到 weibo.com/ajaxlogin.php;如果登錄成功,則跳轉地址為 weibo.com/sso/login.php,該文件返回 302,跳轉到 ajaxlogin.php。

      5. ajaxlogin.php 負責用形如 parent.someMethod({}) 方式調用父窗口 js,處理頁面。

      6. 父窗口 js 刪除 iframe 節點

      7. 同百度

      8. </ol>

        新浪其他 sina.com.cn 子域登錄

        1. 同 weibo

        2. 同 weibo

        3. 同 weibo,但不會刪除 form 節點

        4. 這里有些不同,login.sina.com.cn 下,login.php 的內容用 location.replace() 指向 login.sina.com.cn/crossdomain2.php,由這個頁面調用 parent.someMethod();而在新浪首頁,login.php 中先設置 document.domain='sina.com.cn'(login.php 與頁面域名不完全相同),然后再調用 parent.someMethod()

        5. 父窗口的 js 處理頁面表現,并用jsonp方式(放到script標記的src中)調用 weibo.com/sso/login.php 來完成跨域登錄。

        6. 結束

        7. </ol>

          新浪的登錄 js 并不統一,明顯 weibo 的 js 處理的更精細。

          weibo 登錄中的第 4 步,iframe 中跳轉方式實現對跨域的訪問,顯然有些局限。如果還有其他獨立域名需要訪問,這種跳轉將無法兼顧。

          總結

          上面兩個站點的實現方式基本相同,都是用 iframe 登錄,然后在 iframe 中跳轉來達到通過同一入口進行登錄。難點在于跨域,特別需要注意的是:

          • iframe 中的 js 如果要訪問父窗口的方法,需要保證域名相同,或者主域相同并都設置domain屬性為主域地址,否則瀏覽器會報安全警告。

          • 跨域只要發起跨域的http請求即可,可以放到 script 標記的src中,也可已放到圖片對象的 src 中,推薦后者,因為后者不用放到dom節點中。需要注意的是,這兩種方式都要帶一個每次都不同的參數,可以是時間戳,以防止瀏覽器的自動緩存。

          • </ul>

            上面著重關注了訪問的跳轉順序,還有一個關鍵點是如何標識登錄狀態。上面的方案中,都會在請求跨域文件時,帶上登錄返回的一個唯一字符串,將它作為 一個 token,在后端驗證登錄,識別登錄的用戶。可以把這個 token 設置為很短的時間有效,如1分鐘,并在訪問一次后刪除,可以保證一定的安全性,但是如果在使用前截取,那么可以拿到任何一個地方登錄。因為上面兩個網站對 跨域文件的訪問都是寫在主窗口的js里,因此可以很容易設置斷點獲取之。

            據說 Google 在這點上是安全的,可惜身邊沒法KX上網,留待以后吧。

            補記

            *2013-8-4

            周末有空折騰了一下KX上網,找到個超級好東西:SmartHosts,油Tube/非死book/推ter... 都可以上了。

            Google SSO 實現方式

            Google 所有產品的登錄都是通過 https://accounts.google.com/ 進行處理,基本流程如下:

            1. 在 Google 產品站點擊“登錄”,會跳轉到 https://accounts.google.com/ServiceLogin 登錄;

            2. 表單 post 提交到 https://accounts.google.com/ServiceLoginAuth 驗證;

            3. 登錄成功則直接通過 302 轉到 https://accounts.google.com/CheckCookie,訪問跨域產品的頁面,一般是 accounts.hostname/accounts/SetSID,設置登錄cookie;

            4. 頁面跳轉回登錄來源頁。

            5. </ol>

              針對不同的來源,具體處理上在第3步有些差別:

              • 如果登錄來源是 *.google.com 或 油Tube.com,則直接通過302指向 accounts.油Tube.com/accounts/SetSID,之后該地址再轉向到來源地址。

              • 如果登錄來源是 *.google.com.hk,則返回200,通過 jsonp 請求 accounts.google.com.hk/accounts/SetSID 和 accounts.油Tube.com/accounts/SetSID

              • </ul> </blockquote>

                可以看到,基本原理是一樣的,都是登錄后,訪問一下跨域的頁面,完成登錄信息的cookie設置。

                過程中通過修改 accounts.油Tube.com 的 ip 指向,截取到了登錄后的 /accounts/SetSID 鏈接,直接在一個新的瀏覽器中訪問,是可以完成登錄的。因此,Google 的 token 也不能保證這種截取的安全性。

                原文地址:http://calefy.org/2013/07/31/how-to-achieve-sso-login.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!