## SSO
我們知道如果要登錄系統,就是需要輸入用戶名與密碼,由服務器來做驗證,驗證通過之后就建立session, 然后把session id通過cookie發給人類的瀏覽器,下次人類再訪問URL的時候,會把cookie一并傳過來,這樣系統就知道他們登錄過了。
此時如果一個公司有多個系統,對于同一個用戶,可能密碼還不一樣,能不能**在一個地方登錄一次,就可以訪問所有的系統了?**
有人可能會說,登錄其實就是cookie,如果把cookie共享起來不就可以了?
事實上沒那么簡單 ,因為cookie是不能**跨域**的,a.com產生的cookie,瀏覽器是不會發到b.com上去,所以共享cookie方案不管用。
不過對于同一個公司內部的系統,完全可以統一到一級或者二級域名之下, 比如 xxx.company.com,
但是在登錄前后端沒有保存session,所以當cookie發過來之后,內存沒有數據,無法知道之前是否登錄過,當然談不上驗證。

那么既然有共享cookie,那么session是否可以共享呢?
眾多系統, 架構不同,語言也不同, 共享 session 太麻煩
## token
我們可以同樣借助于cookie,比如用戶在報銷系統登錄了,可以在cookie中寫個token,用戶訪問別的系統的時候,就把token帶過去,那個系統驗證一下token,如果沒問題,就認為它已經登錄了。

每個系統在生成token的時候,需要對數據做個簽名,防止篡改。

- 生成簽名:通過header與userID,使用hash算法和密鑰生成簽名,并且把這個簽名作為token數據一部分
- 收到token,再利用相同算法計算簽名,與發過來的相比,如果相等,說明登錄過,直接取出userID即可。
這里面的問題在于算法和密鑰大家得一致,而且密鑰的分發可能存在風險。
而且token里面放了一個userID,但是每個系統的userID都不一樣,拿過來沒有任何用。
## 統一認證中心
可以建立一個統一認證中心,所有用戶注冊和認證都在這里做。
那么認證中心如何通知每個系統用戶已經認證呢?
比如用戶先訪問系統`www.a.com/pageA`,如果系統發現用戶沒有登錄,需要把它**重定向**到認證中心[www.sso.com/login?redirect=www.a.com/pageA](www.sso.com/login?redirect=www.a.com/pageA)
> redirect后面的url是表示,認證通過之后,還需要重定向回來
瀏覽器放訪問到了認證中心,認證中心就會讓用戶去登錄,登錄成功之后,認證中心需要:
- 建立一個session
- 創建一個ticket(隨機字符串)
- 再重定向到系統A處,url帶著ticket:[www.a.com/pageA?ticket=T123](www.a.com/pageA?ticket=T123), 同時cookie也會發給瀏覽器,比如set cookie: ssoid=1234, sso.com
你可能會說,這個cookie對系統A沒有任何用處,因為跨域不能訪問?
cookie是sso.com的,所以肯定沒有用,瀏覽器只是會保存下來。
但是ticket完全可以用來向認證中心再次做驗證,主要作用是防止有人偽造。

然后瀏覽器會再次訪問[www.a.com/pageA?ticket=T123](www.a.com/pageA?ticket=T123), 然后系統A拿著token,去問認證中心,如果認證中心說這個他們發的,就可以認為用戶在認證中心登錄過了。
此時系統A就為瀏覽器建立session,返回pageA這個資源。
同時,系統A還需要給瀏覽器返回一個cookie,這是屬于系統A的cookie(之前的是SSO的cookie)
```
set cookie:sessionid=xxx,a.com
```
> 注意,瀏覽器實際有兩個cookie,一個是系統A發的,一個是認證中心發的
如果用戶要再訪問系統A的另一個受保護的頁面,[www.a.com/pageA1](www.a.com/pageA1) , 還需要去認證中心登錄嗎?
不用,因為系統A已經給瀏覽器發過自己的cookie,所以瀏覽器會把這個cookie帶過來,這樣就知道它登錄過了。

如果用戶訪問www.a.com/pageA 時已經通過認證中心登錄了,那么再訪問www.b.com/pageB 會發生什么狀態?
和訪問www.a.com/pageA 非常類似,唯一不同的是不需要用戶登錄了,因為瀏覽器已經有了認證中心的cookie, 直接發送給www.so.com 即可。

同樣,認證中心會返回token,www.b.com 需要做驗證

所以,本質上就是一個認證中心的cookie加上多個子系統的cookie而已。
SSO是單點登錄,所以還需要有單點退出。用戶在一個系統退出來,認證中心需要把自己的會話和cookie干掉,然后當需要通知各個系統,讓他們把會話統統干掉,才能實現真正的退出。