1. ID Token - JWT
我們來繼續前兩章( OAuth2 總結 , 對OpenID Connect的理解 )的討論,進入對JWT的理解。先來簡單回顧一下OAuth2和OpenID:
OpenID建立在OAuth之上,完成了認證和授權。而認證和授權的結果就體現在這個ID token之上,而這個ID token通常會是JWT。那麼為什麼會是JWT呢?我們通過以下幾點來逐一解釋。
JWT RFC 7519 給出了官方定義的一些欄位:
當然也不限於此,可以根據自己的需要,添加其他欄位。到此,我們可以看出JWT提供了ID token所需要的能力。一個完整的JTW是由三部分組成:Header,Payload,Signature。三者之間由 . 隔開,剛才提到的認證授權的欄位就存在於Payload中。
Header中存放的是JTW的元數據,包含簽名的演算法以及token的類型,如下所示:
Signature部分是對前兩部分的簽名, 防止數據篡改 。首先,需要指定一個密鑰(secret)。這個密鑰只有伺服器才知道,不能泄露給用戶。然後,使用 Header 裡面指定的簽名演算法(默認是 HMAC SHA256),按照下面的公式產生簽名。
算出簽名以後,把 Header、Payload、Signature三個部分經過base64序列化為三個字元串,再講三個字元串由 . 為間隔拼接成一個字元串返回給客戶端。
ID Token需要有足夠的安全性,JWT是如何做到的呢?
剛看到了簽名部分,簽名的作用只是為了防止數據篡改,而JWT默認是不加密,但也是可以加密的。生成原始 Token 以後,可以用密鑰再加密一次。比如認證伺服器中使用私鑰進行加密,把公鑰分發給其他應用伺服器,應用服務拿到加密後的token後用公鑰解密,獲取到JWT,再用簽名的秘鑰來驗證數據是否經過的篡改。
我們來看看還有神馬其他備選么?Simple Web Tokens (SWT)和Security Assertion Markup Language Tokens (SAML)。
JWT vs SAML:JWT基於json,而SAML基於XML,在大小上就有足夠的優勢,更適用於HTML和HTTP。
JWT vs SWT:在安全性上,SWT只支持對稱加密,而JWT和SAML支持公私鑰的加密方式。
作為一個mobile developer,也想在這里對比一下原先的簡單token模式和SSO中的JWT:
在沒有該機制前,我們通常會使用一個隨機產生的字元串作為token,認證成功後返回給前端,之後前端的每個請求帶上這個token。若後台服務的是個單體應用沒有什麼問題,請求來了,驗證一下token是否有效即可,但當認證服務和其他的應用服務是分離的,怎麼做呢?應用服務受到請求,再向認證服務發起一個請求來驗證驗證token是否合法,是否有許可權訪問該應用服務。這樣做到沒有什麼問題,只是當服務變多時,比如微服務下,勢必會造成認證伺服器的壓力過大。
在使用該機制後,客戶端通過認證服務登錄,獲得這個JWT,之後其他應用服務自身便可以驗證這個token的是否有效,是否有權訪問。
看似完美,但也有它自身的問題,我們來看一個場景:許可權變更。某用戶原先是一個超級管理員,可以訪問所有服務,並可進行任意的刪除,更改操作,他在這個狀態下拿到了JWT。隨後,由於許可權更改為普通管理員,便不應該具有所有許可權,但此時他開始時的JWT被緩存在客戶端仍然可用,其他應用服務也並無法知道這個用戶的許可權已經被更改,後果可想而知了。解決的方式無非是將這個token的有效時間設置的短一些。