SSO
- 單點登錄(SSO: Single Sign-On)
- 一套公用的用戶體系,用戶只要登陸之後,就能夠訪問所有的系統
- 比如登錄了淘寶就不用再登錄天貓了
- 一套公用的用戶體系,用戶只要登陸之後,就能夠訪問所有的系統
- 也用於解決跨域問題
- 參考
JWT
-
JWT就像一個臨時的用戶憑證,代替了用戶名和密碼組合
-
JWT 的目的不是爲了隱藏或者保密數據,而是爲了確保數據確實來自被授權的人創建的(不被篡改)
-
優點
- 爲了確認它是否有效,我們只需要看JWT本身的內容,而不需要藉助於第三方服務或者在多個請求之間將其保存在內存中(session)
- 因爲它本身攜帶了信息驗證碼MAC(Message Authentication Code)
- 爲了確認它是否有效,我們只需要看JWT本身的內容,而不需要藉助於第三方服務或者在多個請求之間將其保存在內存中(session)
-
缺點
- 服務後臺無法拒絕攜帶JWT的請求(如踢除用戶)
- 服務器端沒法統計多少個人登錄了,一個人登錄了多少次,登陸了什麼設備
- 無法很好的控制payload的數據量
- 應該只把認證的相關信息放到payload裏。但實際上,開發人員往往會誤用,把幾乎所有和user相關的數據都放到payload裏
- 會極大的損耗帶寬和IO性能,因爲每次請求都必須把全量的JWT都帶着
-
JWT一般用於身份驗證,不用於儲存會話狀態(代替cookie)
-
它是 JSON 結構的 token,由三部分組成:header,payload,signature
- 格式:
Base64(Header) + "." + Base64(Payload) + "." + $Signature
- header
- JSON對象,用於描述元信息,例如產生 signature 的算法
- payload
- 用於攜帶希望向服務端傳遞的信息
- 由於payload不加密,建議只在其中保存非敏感的用於身份驗證的數據
- signature 用於校驗合法性
- 利用認證服務器的密鑰進行簽名
- 格式:
HS256(Base64(Header) + "." + Base64(Payload), secretKey)
- 也不一定要使用HS256加密
- 格式:
-
客戶端發送方式
- 你可以把JWT放在 Cookie 裏面自動發送,但是這樣不能跨域
- 更好的做法是放在 HTTP 請求的頭信息Authorization字段裏面
Authorization: Bearer<token>
- 或者放在 POST 請求的數據體裏面
-
認證流程
- 用戶向認證服務器提交用戶名和密碼
- 認證服務器也可以和應用服務器部署在一起,但往往是獨立的居多
- 認證服務器校驗用戶名和密碼組合,然後創建一個JWT token,發送給客戶端
- token的Payload裏面包含用戶的身份信息,以及過期時間戳
- 使用私鑰對Header和Payload進行簽名
- 只有認證服務器擁有私鑰
- 客戶端之後的每個HTTP請求中附帶着發送給應用服務器
- 應用服務器使用公鑰檢查JWT簽名,確認Payload確實是由密鑰擁有者簽過名的
- 用戶向認證服務器提交用戶名和密碼
-
爲什麼不直接對payload進行加密
- RSA加密過程比較慢,對於數據比較大的Payload來說,可能會是個問題
- RSA加密過程比較慢,對於數據比較大的Payload來說,可能會是個問題
-
參考:
CAS
- CAS Server起到了一個認證中心的作用,其實所有登錄態都是保持在其所在域名下,所有其他域名下的登錄態都是基於CAS域名下ticket校驗獲得的
- ticket只能使用一次,且有過期時間
- CAS方式不方便持久化數據,session過期或是清除後需要再次獲取授權
- 登錄流程
- Client發起一個A域名(業務域名)下對Server資源的請求;
- Server對請求未通過登錄校驗,返回302請求使Client跳轉至B域名,此時通過query參數帶上A域名回調地址;
- Client在B域名(CAS Server域名)下登錄校驗,同時也會對query參數中A域名回調地址進行校驗域名。通過校驗後,CAS Server返回302請求使Client跳轉至A域名回調地址,並再query參數中帶上ticket參數;
- Server獲取到ticket參數後再請求CAS Server接口進行登錄校驗;
- 可以將登錄狀態信息存儲在Session Server統一管理,進行緩存,減少請求;
- Server將資源返回Client;
- 登出流程
- Client訪問A域名一個指定登出路徑,例如
/api/logout
- Server接收到指定路徑請求後,清除Session Server中的登錄狀態
- Server返回302,使Client重定向至B域名指定路徑,CAS Server接收到請求後,清除全部該用戶登錄狀態
- Client訪問A域名一個指定登出路徑,例如
OAuth2
- OAuth2是讓第三方應用不需要用戶名密碼讀取指定用戶數據的一個認證過程
- 如果權限控制不好,通過oauth方式授權,第三方應用可以憑藉他手中的授權"憑證" (access token) 做一些他想做的事情,比如直接幫你關注某個微博賬號
- 第三方登錄授權流程(以GitHub賬號登錄A網站爲例)
- 登陸前
- A網站向GitHub 登記自己身份
- https://github.com/settings/applications/new
- 需要提供主頁和回調網址
- GitHub返回client ID和client secret
- A網站向GitHub 登記自己身份
- 登陸時
- A網站跳轉到GitHub認證網頁
- 同時帶上client ID, 回調網址和授權範圍等信息
- GitHub要求用戶登錄並詢問是否允許授權A網站
- 用戶同意,GitHub 就會重定向回 A 網站註冊的跳轉網址,同時附上一個授權碼(code)
- 該碼的有效期應該很短,通常設爲10分鐘,客戶端只能使用該碼一次,否則會被授權服務器拒絕
- 該碼與客戶端ID和重定向URI,是一一對應關係
- A 網站使用授權碼,向 GitHub 請求令牌
- 需要提供client_id, client_secret ,code
- 令牌有過期時間和權限範圍
- A 網站使用Github返回的令牌(accessToken),向 GitHub 請求用戶數據
- 這一步是在客戶端的後臺的服務器上完成的
- A網站的後端將 token 存儲下來,同時將用戶可以公開的信息通過 cookie、JWT 等形式返回給前端
- A網站跳轉到GitHub認證網頁
- 爲什麼第一次要返回code,而不是token?
- 授權碼通過前端傳送給用戶,在由用戶通過前端給給A網站,容易造成令牌泄露
- A網站與GitHub的交互是在後端通過HTTPS安全連接交互的
- 這樣的前後端分離,可以避免令牌泄漏
- 即使黑客截獲了 code,他沒有那串預先商量好的client_secret,也是無法獲取 token 的
- 如果是純前端應用,則直接返回token
- 這樣很不安全的,因此只能用於一些安全要求不高的場景,並且令牌的有效期必須非常短
- 爲什麼要返回令牌而不是直接返回用戶數據?
- 因爲A網址可能一段時間後又需要請求該數據或者需要請求其他數據,此時可以複用令牌,而不用再次鑑權
- 登陸前
CAS與OAuth2區別
(A爲用戶,B爲要登錄的應用,C爲CAS服務,D爲oauth2 服務提供者)
- 保護資源的位置不同
- CAS 的單點登錄,保障的是B資源的安全
- 資源在 D這一方,保障的是D資源的安全,B是想索取D的用戶的資源
- B要獲取的信息不同
- 對於CAS,B要獲取的最終信息是,這個用戶到底有沒有權限訪問我的資源
- 對於OAuth2, B獲取的最終信息是,D的用戶資源到底能不能讓B訪問
- 獲取信息的流程不同
- CAS 通過 token 校驗的時候,不需要傳預先設定的secret
- OAuth 通過 code 換取 token 的時候,需要傳secret
- 支持的功能不同
- CAS只用於身份識別和認證
- OAuth除了支持身份識別和認證,也支持授授權