sso和oauth2.0的簡單瞭解學習

       sso,單點登錄,single sign on 縮寫。sso多用於多個應用之間的切換,例如百度論壇、百度知道、百度雲、百度文庫等,在其中一個系統中登錄,(登錄有效期內)切換到另一個系統的時候,不必再次輸入用戶名密碼。
       oauth2.0,開放授權,不兼容oauth1.0.允許第三方應用代表用戶獲得訪問權限。可以作爲web應用、桌面應用和手機等設備提供專門的認證流程。例如,用qq賬號登錄豆瓣、美團、大衆點評;用支付寶賬號登錄淘寶、天貓等。
       sso和oauth2.0在應用場景上的區別在於,使用sso的各個系統(子模塊)之間是互相信任的,通常是一個廠家的產品,或者是一個產品的不同模塊系統。使用oauth2.0的各個應用之間是互相不信任的,通常是不同廠家之間的賬號共享。
      常規的身份認證流程:1.登錄頁,我們提交username和pwd;2.server進行身份識別認證,認證通過後將用戶信息寫入session,同時瀏覽器將身份信息寫入cookie;3.訪問其他頁面的時候,瀏覽器請求會帶上cookie,服務端根據cookie找到對應session,相當於完成身份認證。這就是早期通過盜取cookie,模擬用戶通過身份驗證的原理。
       在瞭解sso和oauth2.0之前,我們必須知道的幾個常識:
       1.cookie不能跨域。
       2.session是存在於各自應用中的,不能共享。
       sso分爲同域下的單點登錄和不同域名下的單點登錄。先說同域名下的單點登錄,嚴格來說這不是sso。同域名下情況又分爲兩種,但是思路是一致的,共享cookie,共享session。
       第一類:www.a.com/site1和www.a.com/site2,瀏覽器在存儲cookie的時候會將域名記錄爲www.a.com,如果不做特殊處理,sessionid是一致的。
       第二類:app1.a.com和app2.a.com,主域名一致,不同子域名。這種情況下可以在寫cookie時,將域名指定爲頂級域名,即a.com。但是注意兩個應用的sessionid可是不一致的,兩個應用會各自記錄自己的sessionid,在登錄的時候並不影響,但是退出的時候就會有問題了。
       模擬操作如下:登錄app1.a.com,用戶輸入用戶名密碼,身份認證成功,app1的session1創建,瀏覽器添加cookie【域名爲a.com】,登錄app2.a.com,瀏覽器攜帶域名爲a.com的cookie,此時系統檢查到app2的session2不存在,然後驗證cookie攜帶的身份信息,身份認證通過,session2創建。到此用戶輸入一次用戶名密碼可以登錄兩個系統。但是退出的時候如果從app1退出,只會清除session1和cookie,session2還在,意味着app2還是登錄狀態。這就需要將各個系統的session共享,不同語言有不同的框架根據實際情況來選擇解決方案。
       下面來說真正的sso。在說sso之前,我們先說cas的流程,集中式認證服務是一種針對萬維網的單點登錄協議,這個協議定義了單點登錄的標準流程,時序圖如下。

  簡單翻譯如下:
  1.用戶訪問app1,瀏覽器向app1發出請求。【未登錄狀態】
  2.app1收到請求後,發現瀏覽器處於未登錄狀態,返回一個302,跳轉訪問cas,並附帶returnurl【即aap1自身地址】。
  3.瀏覽器收到302後,訪問cas。
  4.cas返回給瀏覽器一個登錄頁。
  5.瀏覽器展示登錄頁,用戶攜帶returnurl提交用戶名密碼到cas。
  6.cas進行身份認證,認證成功創建sso的session和認證ticket(ST),返回302,並將ticket一併返回給瀏覽器
  7.瀏覽器記錄cookie,帶着ticket(ST)訪問returnurl【app1地址】。(cookie是cas的)
  8.app1收到請求後,向cas確認ticket(ST)是否有效。
  9.cas驗證ticket通過後,返回200給app1。
  10.app1記錄登錄狀態並響應瀏覽器請求(步驟7),返回302到自身(不帶ST)。(添加app1的cookie)
  11.瀏覽器收到302,訪問app1地址,此時cookie和session齊全,身份認證完成,向瀏覽器返回請求的資源。之後(cookie、session有效期內)訪問app1,不必再身份驗證,直接返回請求資源。【app1登錄完成】
  此時app1登錄已經完成,當切換到app2的時候,流程如下:
  12.用戶訪問app2,瀏覽器向app2發出請求。【app2未登錄】
  13.app2收到請求,發現瀏覽器處於未登錄狀態,返回一個302,跳轉訪問cas,並附帶returnurl【即aap2自身地址】。
  14.瀏覽器收到302,訪問cas。(由於步驟7已經記錄的cas的cookie,瀏覽器會在請求時將cookie攜帶)
  15.cas驗證身份,由於有cookie存在,直接返回票據ticket(ST2),並讓瀏覽器重定向。
  16.瀏覽器帶着ticket(ST2)訪問returnurl。
  17.app2收到請求後,向cas確認ticket(ST2)是否有效。
  18.cas驗證ticket通過後,返回200給app2。
  19.app2記錄登錄狀態並響應瀏覽器請求(步驟16),返回302到自身(不帶ST)。(添加app2的cookie)
  20.瀏覽器收到302,訪問app2地址,此時cookie和session齊全,身份認證完成,向瀏覽器返回請求的資源。之後(cookie、session有效期內)訪問app2,不必再身份驗證,直接返回請求資源。【app2登錄完成】
  此時app2登錄完成,app間單點登錄就實現了。其實我一直在思考6-9和13-17這個過程中的ticket(ST)的作用,起初有疑惑:爲什麼cas通過身份驗證後,不直接將身份信息給app,而是通過302將用戶信息和ticket給瀏覽器,讓瀏覽器再次訪問app,app通過cas驗證ticket(ST)來確保身份有效?這樣兜了一大圈造成很多次系統間的跳轉訪問,降低了效率。後來假設了一種情況:cas將身份信息直接給app(此時應不會再生成ticket,app也無需向cas驗證ticket的有效性),那瀏覽器在沒有通過cas驗證的情況下,直接僞造身份信息,app是否也認爲登錄了呢?這種邏輯下,app是一定會允許僞造的身份訪問請求資源的。
  sso已經簡單介紹完了,下面再看看oauth2.0。oauth2.0的理解我們不妨來模擬這樣一個場景:
  小單同學經朋友介紹第一次使用美團,註冊美團賬號的時候,頁面上有賬號登錄和快捷登錄兩種方式。快捷登錄方式可以暫不註冊,直接使用qq賬號、微信賬號和微博賬號進行登錄。由於較懶,小單同學選擇了快捷登錄,界面跳轉到一個授權登錄頁面,授權隱私內容包括用戶暱稱、用戶頭像等等,選擇同意授權,在彈出的qq快捷登錄頁面上同意授權之後,界面跳轉到美團的首頁。
  oauth2.0定義了四個角色:客戶端client,資源所有者resource owner ,資源服務器resource server,授權服務器Authorization server。結合上面的場景,不難看出美團是客戶端,我們用戶是資源的所有者,微信的用戶信息放在了資源服務器上,對賬戶授權的工作放在了授權服務器上。直覺上資源服務器和授權服務器應該是一起的,但是實際項目中,這兩個服務器獨立部署更便於保護用戶的數據信息。

  oauth2.0的運行流程看起來比sso的簡單點,解釋如下:

  A,客戶端要求用戶給與授權。我們打開美圖,選擇快速登錄。
  B,用戶同意授權給客戶端。我們選擇了用qq賬號快速登錄,同意授權給美團我們的用戶信息。
  C,客戶端拿到用戶給的授權,先授權服務器申請令牌。美圖向qq的授權服務器發起申請。
  D,認證服務器對客戶端進行認證,確認無誤發放令牌。通常手機端會切換到qq端,驗證登錄狀態,提示是否授權,我們確認登錄之後,服務器發放令牌。
  E,客戶端使用令牌,申請資源。美團向qq申請用戶信息。
  F,資源服務器確認令牌無誤,同意開放資源。我們用qq的賬號登錄了美團,美團上顯示我們的qq暱稱、頭像等信息。
  oauth2.0定義了四種授權類型:授權碼模式authorization code、簡化模式 implict、密碼模式resource owner password credentials 和 客戶端模式 client credentials。授權碼模式爲功能最爲完整,流程最爲嚴密的授權,其他模式爲授權碼模式的變體或簡化,下面簡要介紹授權碼模式。
  授權碼模式基於重定向跳轉,所以客戶端必須能與user-agent(一般爲用戶瀏覽器)交互,通過user-agent路由來發送實際的授權碼。(理解前半句就好,後半句大家機翻理解了就理解,不理解問題也不大)

 

  繼續套用上面的應用場景,各角色對應爲client(美團),user-agent(瀏覽器),resource owner(用戶,我們自己),authorization server(qq授權服務器),resource server(qq資源服務器)。我們在實際操作的時候會發現我們沒有操作瀏覽器,其實是app本身(美團)內部已經集成了瀏覽器的功能(作用比功能更恰當一些),所以我們沒有發現client調用user-agent,但其實這個流程是沒有少的。
  1.client構造了一個用於申請authorization code的請求。通常會有response_type(表明正在申請授權流流程),client_id(客戶端的身份id),redirect_url(收到請求的跳轉地址),scope(權限範圍,或者訪問級別),state(隨機字符串,防止csrf攻擊)這樣幾個參數。
  2.當resource owner 訪問步驟一構造的請求,授權服務就跳轉到了這裏,由用戶選擇是否授權。
  3.當用戶選擇授權登錄,授權服務器就會提供授權碼,跳轉到redirect_url地址。授權碼的有效時間不等,取決於授權服務器設置。
  4.客戶端拿到授權碼,向授權服務器申請token。
  5.授權服務器根據步驟4中提交的授權碼及身份信息等,決定是否給客戶端發放token。
  token結構中包含access_token(本次使用的門票),expires_in(本次門票的有效期),refresh_token(下次使用的門票)這三個重要部分和其他內容。當本次門票過期失效的時候,我們用用refresh_token來申請訪問,授權服務器會再次生成新的token,而不必再進行一次步驟1-4。這樣就實現了完整的第三方登錄認證。
  相比之下implict簡化模式,更適用於webapp和移動應用。簡化模式不通過第三方應用程序(瀏覽器),直接向認證服務器申請令牌token,跳過了授權碼的步驟。
  而resource owner password credentials密碼模式則要求用戶在登錄客戶端的時候輸入用戶名密碼,客戶端不能保存用戶名密碼,而是向授權服務器進行認證。這種模式通常用於客戶端是操作系統的一部分,或者(client、resource server)是一個公司出品。
  嚴格來說 client credentials客戶端模式是由客戶端以自己的名義向授權服務器進行認證,並不是以用戶的名義,因此不屬於oauth框架要解決的範疇。
  oauth2.0詳細請參考:https://tools.ietf.org/html/rfc6749

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章