轉載源:https://www.jianshu.com/p/613c615b7ef1web
來源於做者劉欣的《碼農翻身》 + 本身的備註理解redis
這家集團公司財大氣粗,居然本身建了一個數據中心, 放了數百臺機器, 部署了幾十個企業內部系統。算法
在無塵、恆溫、恆溼的環境裏,這些信息系統的日子過得很是愜意。json
他們只須要在白天應對人類的HTTP 請求,及時作出響應, 只要人類一下班, 系統的負載就陡然降低,CPU內存所有都空閒下來。 你們閒來無事, 熱熱鬧鬧的機房夜話就開始了。後端
休假系統是用世界上最好的語言PHP作的,他向來消息靈通,今天帶來了一個特別新聞:「 號外號外, 據說了嗎, 人類要搞SSO
了。」跨域
Python 寫的報銷系統, C#寫的車輛管理系統早就看不慣PHP這種中英混雜的風格了: 「 別拽了,說中文!」瀏覽器
PHP休假系統很不屑: 「就是單點登陸
嘛,難道大家沒據說過?」安全
C# 說: 「不就是登陸嘛! 人類不是每天登陸系統? 你看他們想調度車倆的時候,就得登陸個人系統, 輸入用戶名和密碼, 我作驗證, 驗證經過就創建session, 而後把session id 經過cookie發送給人類的瀏覽器, 下次人類再訪問個人URL的時候, cookie就會發過來, 我就知道他已經登陸過了。
「服務器
C#很得意,向你們炫耀着登陸的原理。cookie
「對了,告訴大家一個小祕密, 人類這些密碼太簡單了,不是123456, 就是abcd。 」
Python附和道: 「 是啊,人類太懶了, 密碼超級簡單,據說上一次有個傢伙用領導帳號成功地登陸了系統, 因而全集團人員的工資都暴露了! 」
「那對於同一我的, 你這裏的用戶名/密碼和小C#那裏會同樣嗎?」 PHP說
「這個。。。 頗有可能不同。」
PHP說: 「對啊,這就是問題了, 這麼多不一樣的用戶名,有的是郵箱地址,有的是手機號,有的是用戶名, 咱們這裏幾十個系統,擱誰都記不全啊! 這就是他們爲何要搞單點登陸:在一個地方登陸一次, 就能夠訪問咱們這裏全部的系統了」
C# 叫道: " 只須要登陸一次? 聽起來很美好啊 ! 讓我想一想怎麼實現, 對了, 登陸就是cookie,那咱們把cookie共享起來不就能夠了? 人類在報銷系統那裏登陸後,再訪問我這個車輛管理系統, 把cookie發過來不就好了?"
衆人紛紛表示贊同。
PHP 內心再次鄙視了一下C# , 說: 「NO , NO , cookie是不能跨域的
, a.com 產生的cookie , 瀏覽器是不會發到b.com去的。 」
有人在悄悄地google , PHP果真說得不錯。
你們趕忙檢查了下本身的域名,有的叫 xxx.vaction.com, 有的叫xxx.hr.com , 看來共享cookie方案無論用。
PHP補充到: 「也許人類能把咱們統一到一級或二級域名下, 好比 xxx.company.com, 這樣cookie能夠共享了! 可是咱們後端沒有session 也不行啊, 你cookie發過來,我內存中沒數據,根本不知道你是否登陸過, 怎麼驗證?」
C#說: 「session 也能夠共享哦 , 你看我這個系統有兩個服務器,共享的是redis中的session, 未來咱們這幾十個系統都共享同一個redis,想一想都讓人激動啊!」
Python 說: 「 這麼多系統, 架構不一樣,語言也不一樣, 共享session太麻煩了吧? 」
C# 發愁地說: 「那怎麼辦? 」
這時候旁邊傳來了一聲大吼: 「大家在那裏吵吵什麼,老子在生成報表,都無法專心幹活了!」
這是脾氣暴躁的COBOL在抱怨了, 千萬不要惹這個老傢伙,因而你們紛紛噤聲, 老老實實地睡覺去了。
單點登陸(Single Sign On),簡稱爲 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只須要登陸一次就能夠訪問全部相互信任的應用系統。
咱們目前的系統存在諸多子系統,而這些子系統是分別部署在不一樣的服務器中,那麼使用傳統方式的session是沒法解決的,咱們須要使用相關的單點登陸技術來解決。
次日晚上,COBOL程序終於歇着了, 你們繼續討論。
Python提了一個新點子:「要我說,咱們別共享session了, 咱們就用cookie, 用戶在我這個報銷系統這裏登陸了, 我就在cookie中寫個token , 用戶訪問別的系統,就能夠把token 帶過去, 那個系統驗證一下token ,若是沒問題,就認爲它已經登陸了。」
「那token 得加密吧, 要否則誰均可以僞造」 C#安全意識挺強
「那是天然, 據說過json web token 沒有? 咱們每一個系統在生成token 的時候,都要對數據作個簽名,防止別人篡改, 下面就是我生產的token , 其中有header 信息和userID, 你看我用Hash算法和密鑰生產了一個簽名。 這個簽名啊也是token數據的一部分, 到時候也會發到你的系統去」 Python 說。
C#說: 「明白了, 我收到了token ,就用一樣的算法再計算簽名,而後和你計算的相比, 若是相等,證實他登陸過,我能夠直接取出userID使用了, 若是不相等, 說明有人篡改, 我就關門放狗, 把他暴揍一頓。」
Ruby 插嘴說: 「這個辦法不錯,輕量級,我喜歡! 只是這個算法和密鑰你們都得一致才行。 密鑰的分發也是個問題。」
PHP聽了半天, 發現了一個漏洞:「你這個token中放了一個userID, 但是咱們每一個系統的userID都不同啊, 你的userID 我拿過來沒有任何用處, 怎麼辦?」
這的確是個致命的問題!每一個系統中都有一套本身獨特的user id ,互不共享
,這樣以來以前討論的什麼共享session, 共享cookie ,都很難實現了 !
一陣沉默, 看來沒救了。
夜已深,你們討論得有點累了,紛紛睡去。
第三天,機房夜話繼續, 但仍是沒有解決方案。氣氛有點小尷尬。
老成持重的Java咳嗽了幾聲,示意要發言了。
「大家知道嗎, 咱們是一個企業內部系統,人類搞SSO就是想消除這多個帳號的問題,未來每一個系統都不須要維護本身的用戶系統, 他們會創建一個統一的認證中心
,全部的用戶註冊和認證都在那裏作。」
「這麼作行得通嗎,認證中心怎麼通知咱們說用戶已經認證了?」 C#問道
「這個過程稍微有點複雜」 , Java 對C# 說, 「舉個例子來解釋下, 好比用戶經過瀏覽器先訪問你這個系統www.a.com/pageA , 這個pageA是個須要登陸才能訪問的頁面,你發現用戶沒有登陸, 這時候你須要作一件額外的操做,就是重定向到認證中心,www.sso.com/login?redirect=www.a.com/pageA」
C#說: 「爲何後面要跟一個redirect的url呢? 奧,明白了, 未來認證經過後,還要重定向到我這裏來。」
「沒錯, 瀏覽器會用這個www.sso.com/login?redirect=www.a.com/pageA 去訪問認證中心, 認證中心一看, 沒登陸過, 認證中心就讓用戶去登陸, 登陸成功之後, 認證中心要作幾件重要的事情 :
1. 創建一個session。
2. 建立一個ticket (能夠認爲是個隨機字符串)
3. 而後再重定向到你那裏, url 中帶着ticket : www.a.com/pageA?ticket=T123 與此同時cookie也會發給瀏覽器,好比:Set cookie : ssoid=1234, sso.com 」
「但是這個cookie對我一點用處都沒有啊,跨域不能訪問啊。」
「人家網站sso.com的cookie對你確定沒用了, 瀏覽器會保存下來。 可是注意那個ticket 」 Java 提醒道, 「這個東西是個重要的標識,你拿到之後須要再次向認證中心作驗證。」
「明白,是爲了防止不壞好意的人僞造」
「你拿着token ,去問下認證中心, 這是您發的token 嗎, 認證中心說沒錯,是我發的,那你就能夠認爲用戶在認證中心登陸過了」
「那我該幹什麼事情呢? 」
「瀏覽器向你發出的請求不是www.a.com/pageA?ticket=T123 嗎, 這時候你既然認爲用戶已經登陸過了,那就給他創建session, 返回pageA這個資源啊」
「嗯, 我還須要給瀏覽器發一個cookie, 對吧, 這是屬於個人cookie : Set cookie : sessionid=xxxx, a.com 」 C# 說道
"孺子可教, 注意,這時候瀏覽器實際上有兩個cookie,一個是你發的,另一個是認證中心發的。"
「若是用戶再次訪問我另一個受保護的頁面,www.a.com/pageA1, 該怎麼辦? 難道還要去認證中心登陸 」 C#繼續問
「那固然不用了,你給瀏覽器發過你本身的cookie , 到時候瀏覽器天然會帶過來,你就知道它登陸過了。 」
「原來如此, 好麻煩啊」 C#感慨道。
Python 插了一句: 「若是用戶訪問C#的系統(www.a.com/pageA)時已經經過認證中心登陸了, 而後再訪問我www.b.com/pageB, 會發生什麼情況呢?」
Java 說:「很簡單, 和訪問www.a.com/pageA很是相似,惟一的不一樣就是不須要用戶登陸了,由於瀏覽器已經有了認證中心的cookie, 直接發給www.sso.com就能夠了」
說着, Java 又畫了兩張圖。
一樣,認證中心會返回token , www.b.com 須要作驗證
PHP 一直在努力的聽,他說: 「其實本質上就一個認證中心的cookie ,加上多個子系統的cookie 而已!」
Java 撇了一眼PHP : 「總結的很精闢!」
C#發現了一點新東西: 「在認證中心,爲何要去作一個系統註冊的操做呢?, 我看到註冊了系統A,還有系統B」
"SSO 是單點登陸,是否是還要有單點退出啊, 用戶在一個系統退出了,認證中心須要把本身的會話和cookie幹掉,而後還要去通知各個系統, 讓他們把本身的會話通通幹掉,這樣才能在全部的系統都實現真正地退出啊。" Java回答。
你們琢磨了一下子,很快就喧囂起來:
「太麻煩了」
「咱們的代碼還得改動很多呢」
「重定向太多了, 把我都搞暈了」
「我以爲人類不會這麼搞!」
......
Java 說「別小看它, 這個點子是耶魯大學提出的,叫作CAS(Central Authentication Server ) , 是一個很著名的SSO解決方案, 弄很差人類就會採用。 大家吶,仍是好好學學吧。
CAS 是 Yale 大學發起的一個開源項目,旨在爲 Web 應用系統提供一種可靠的單點登陸方法,CAS 在 2004 年 12 月正式成爲 JA-SIG 的一個項目。CAS 具備如下特色:
【1】開源的企業級單點登陸解決方案。
【2】CAS Server 爲須要獨立部署的 Web 應用。
【3】CAS Client 支持很是多的客戶端(這裏指單點登陸系統中的各個 Web 應用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
從結構上看,CAS 包含兩個部分: CAS Server 和 CAS Client。CAS Server 須要獨立部署,主要負責對用戶的認證工做;CAS Client 負責處理對客戶端受保護資源的訪問請求,須要登陸時,重定向到 CAS Server。下圖是 CAS 最基本的協議過程: