天天看點

使用jwt完成sso單點登入

JWT

在了解jwt之前,先了解一下常用的會話管理

  • 基于

    server-session

    的管理方式
  • cookie-based

    的管理方式
  • token-based

    的管理方式

一.基于

server-session

的管理

  1. 服務端

    session

    是使用者第一次通路應用時,伺服器就會建立的對象,代表使用者的一次會話過程,伺服器為每一個

    session

    都配置設定一個唯一的

    sessionid

    ,以保證每個使用者都有一個不同的

    session

    對象。
  2. 伺服器在建立完

    session

    後,會把

    sessionid

    通過

    cookie

    傳回給使用者所在的浏覽器,這樣當使用者第二次及以後向伺服器發送請求的時候,就會通過

    cookie

    sessionid

    傳回給伺服器,以便伺服器能夠根據

    sessionid

    找到與該使用者對應的

    session

    對象。
  3. session

    通常有失效時間的設定,比如2個小時。當失效時間到,伺服器會銷毀之前的

    session

    ,并建立新的

    session

    傳回給使用者。但是隻要使用者在失效時間内,有發送新的請求給伺服器,通常伺服器都會把他對應的

    session

    的失效時間根據目前的請求時間再延長2個小時。
  4. session

    在一開始并不具備會話管理的作用。它隻有在使用者登入認證成功之後,并且往

    session

    對象裡面放入了使用者登入成功的憑證,才能用來管理會話。管理會話的邏輯也很簡單,隻要拿到使用者的

    session

    對象,看它裡面有沒有登入成功的憑證,就能判斷這個使用者是否已經登入。當使用者主動退出的時候,會把它的

    session

    對象裡的登入憑證清掉。是以在使用者登入前或退出後或者

    session

    對象失效時,肯定都是拿不到需要的登入憑證的。

以上過程可簡單使用流程圖描述如下: 

使用jwt完成sso單點登入

它還有一個比較大的優點就是安全性好,因為在浏覽器端與伺服器端保持會話狀态的媒介始終隻是一個

sessionid

串,隻要這個串夠随機,攻擊者就不能輕易冒充他人的

sessionid

進行操作;除非通過CSRF或http劫持的方式,才有可能冒充别人進行操作;即使冒充成功,也必須被冒充的使用者

session

裡面包含有效的登入憑證才行。但是在真正決定用它管理會話之前,也得根據自己的應用情況考慮以下幾個問題:

  1. 這種方式将會話資訊存儲在web伺服器裡面,是以在使用者同時線上量比較多時,這些會話資訊會占據比較多的記憶體;
  2. 當應用采用叢集部署的時候,會遇到多台web伺服器之間如何做

    session

    共享的問題。因為

    session

    是由單個伺服器建立的,但是處理使用者請求的伺服器不一定是那個建立

    session

    的伺服器,這樣他就拿不到之前已經放入到

    session

    中的登入憑證之類的資訊了;
  3. 多個應用要共享

    session

    時,除了以上問題,還會遇到跨域問題,因為不同的應用可能部署的主機不一樣,需要在各個應用做好

    cookie

    跨域的處理。

針對問題1和問題2,我見過的解決方案是采用

redis

這種中間伺服器來管理

session

的增删改查,一來減輕web伺服器的負擔,二來解決不同web伺服器共享

session

的問題。針對問題3,由于服務端的

session

依賴

cookie

來傳遞

sessionid

,是以在實際項目中,隻要解決各個項目裡面如何實作

sessionid

cookie

跨域通路即可,這個是可以實作的,就是比較麻煩,前後端有可能都要做處理。

二. 

cookie-based

的管理方式

由于前一種方式會增加伺服器的負擔和架構的複雜性,是以後來就有人想出直接把使用者的登入憑證直接存到用戶端的方案,當使用者登入成功之後,把登入憑證寫到

cookie

裡面,并給

cookie

設定有效期,後續請求直接驗證存有登入憑證的

cookie

是否存在以及憑證是否有效,即可判斷使用者的登入狀态。使用它來實作會話管理的整體流程如下:

  1. 使用者發起登入請求,服務端根據傳入的使用者密碼之類的身份資訊,驗證使用者是否滿足登入條件,如果滿足,就根據使用者資訊建立一個登入憑證,這個登入憑證簡單來說就是一個對象,最簡單的形式可以隻包含使用者

    id

    ,憑證建立時間和過期時間三個值。
  2. 服務端把上一步建立好的登入憑證,先對它做數字簽名,然後再用對稱加密算法做加密處理,将簽名、加密後的字串,寫入

    cookie

    cookie

    的名字必須固定(如

    ticket

    ),因為後面再擷取的時候,還得根據這個名字來擷取

    cookie

    值。這一步添加數字簽名的目的是防止登入憑證裡的資訊被篡改,因為一旦資訊被篡改,那麼下一步做簽名驗證的時候肯定會失敗。做加密的目的,是防止

    cookie

    被别人截取的時候,無法輕易讀到其中的使用者資訊。
  3. 使用者登入後發起後續請求,服務端根據上一步存登入憑證的

    cookie

    名字,擷取到相關的

    cookie

    值。然後先做解密處理,再做數字簽名的認證,如果這兩步都失敗,說明這個登入憑證非法;如果這兩步成功,接着就可以拿到原始存入的登入憑證了。然後用這個憑證的過期時間和目前時間做對比,判斷憑證是否過期,如果過期,就需要使用者再重新登入;如果未過期,則允許請求繼續。
使用jwt完成sso單點登入

這種方式最大的優點就是實作了服務端的無狀态化,徹底移除了服務端對會話的管理的邏輯,服務端隻需要負責建立和驗證登入

cookie

即可,無需保持使用者的狀态資訊。對于第一種方式的第二個問題,使用者會話資訊共享的問題,它也能很好解決:因為如果隻是同一個應用做叢集部署,由于驗證登入憑證的代碼都是一樣的,是以不管是哪個伺服器處理使用者請求,總能拿到

cookie

中的登入憑證來進行驗證;如果是不同的應用,隻要每個應用都包含相同的登入邏輯,那麼他們也是能輕易實作會話共享的,不過這種情況下,登入邏輯裡面數字簽名以及加密解密要用到的密鑰檔案或者密鑰串,需要在不同的應用裡面共享,總而言之,就是需要算法完全保持一緻。

這種方式由于把登入憑證直接存放用戶端,并且需要

cookie

傳來傳去,是以它的缺點也比較明顯:

  1. cookie

    有大小限制,存儲不了太多資料,是以要是登入憑證存的消息過多,導緻加密簽名後的串太長,就會引發别的問題,比如其它業務場景需要

    cookie

    的時候,就有可能沒那麼多空間可用了;是以用的時候得謹慎,得觀察實際的登入

    cookie

    的大小;比如太長,就要考慮是非是數字簽名的算法太嚴格,導緻簽名後的串太長,那就适當調整簽名邏輯;比如如果一開始用4096位的RSA算法做數字簽名,可以考慮換成1024、2048位;
  2. 每次傳送

    cookie

    ,增加了請求的數量,對通路性能也有影響;
  3. 也有跨域問題,畢竟還是要用

    cookie

前面兩種會話管理方式因為都用到

cookie

,不适合用在native app裡面:native app不好管理

cookie

,畢竟它不是浏覽器。這兩種方案都不适合用來做純api服務的登入認證。要實作api服務的登入認證,就要考慮下面要介紹的第三種會話管理方式。

三.

token-based

的管理方式

這種方式從流程和實作上來說,跟

cookie-based

的方式沒有太多差別,隻不過

cookie-based

裡面寫到

cookie

裡面的

ticket

在這種方式下稱為

token

,這個

token

在傳回給用戶端之後,後續請求都必須通過url參數或者是http header的形式,主動帶上

token

,這樣服務端接收到請求之後就能直接從http header或者url裡面取到token進行驗證:

使用jwt完成sso單點登入

這種方式不通過

cookie

進行

token

的傳遞,而是每次請求的時候,主動把

token

加到http header裡面或者url後面,是以即使在native app裡面也能使用它來調用我們通過web釋出的api接口。app裡面還要做兩件事情:

  1. 有效存儲

    token

    ,得保證每次調接口的時候都能從同一個位置拿到同一個

    token

  2. 每次調接口的的代碼裡都得把

    token

    加到header或者接口位址裡面。

看起來麻煩,其實也不麻煩,這兩件事情,對于app來說,很容易做到,隻要對接口調用的子產品稍加封裝即可。

這種方式同樣适用于網頁應用,

token

可以存于

localStorage

或者

sessionStorage

裡面,然後每發ajax請求的時候,都把

token

拿出來放到ajax請求的header裡即可。不過如果是非接口的請求,比如直接通過點選連結請求一個頁面這種,是無法自動帶上

token

的。是以這種方式也僅限于走純接口的web應用。

這種方式用在web應用裡也有跨域的問題,比如應用如果部署在a.com,api服務部署在b.com,從a.com裡面發出ajax請求到b.com,預設情況下是會報跨域錯誤的,這種問題可以用CORS(跨域資源共享)的方式來快速解決。

這種方式跟

cookie-based

的方式同樣都還有的一個問題就是

ticket

或者

token

重新整理的問題。有的産品裡面,你肯定不希望使用者登入後,操作了半個小時,結果

ticket

或者

token

到了過期時間,然後使用者又得去重新登入的情況出現。這個時候就得考慮

ticket

token

的自動重新整理的問題,簡單來說,可以在驗證

ticket

token

有效之後,自動把

ticket

token

的失效時間延長,然後把它再傳回給用戶端;用戶端如果檢測到伺服器有傳回新的

ticket

token

,就替換原來的

ticket

token

四. 安全問題

在web應用裡面,會話管理的安全性始終是最重要的安全問題,這個對使用者的影響極大。

首先從會話管理憑證來說,第一種方式的會話憑證僅僅是一個

sessionid

,是以隻要這個

sessionid

足夠随機,而不是一個自增的數字id值,那麼其它人就不可能輕易地冒充别人的

sessionid

進行操作;第二種方式的憑證

ticket

以及第三種方式的憑證

token

都是一個在服務端做了數字簽名,和加密處理的串,是以隻要密鑰不洩露,别人也無法輕易地拿到這個串中的有效資訊并對它進行篡改。總之,這三種會話管理方式的憑證本身是比較安全的。

然後從用戶端和服務端的http過程來說,當别人截獲到用戶端請求中的會話憑證,就能拿這個憑證冒充原使用者,做一些非法操作,而伺服器也認不出來。這種安全問題,可以簡單采用https來解決,雖然可能還有http劫持這種更高程度的威脅存在,但是我們從代碼能做的防範,确實也就是這個層次了。

JWT介紹 (https://jwt.io/)

JSON Web Token(JWT)

是一個開放标準(RFC 7519),它定義了一種緊湊和自包含的方式,用于在各方之間作為JSON對象安全地傳輸資訊。作為标準,它沒有提供技術實作,但是大部分的語言平台都有按照它規定的内容提供了自己的技術實作,是以實際在用的時候,隻要根據自己目前項目的技術平台,到官網上選用合适的實作庫即可。

使用

JWT

來傳輸資料,實際上傳輸的是一個字元串,這個字元串就是所謂的json web token字元串。是以廣義上,

JWT

是一個标準的名稱;狹義上,

JWT

指的就是用來傳遞的那個

token

字元串。這個串有兩個特點: 

1. 緊湊:指的是這個串很小,能通過url 參數,http請求送出的資料以及http header的方式來傳遞; 

2. 自包含:這個串可以包含很多資訊,比如使用者的id、角色等,别人拿到這個串,就能拿到這些關鍵的業務資訊,進而避免再通過資料庫查詢等方式才能得到它們。

通常一個

JWT

是長這個樣子的:

使用jwt完成sso單點登入

要知道一個

JWT

是怎麼産生以及如何用于會話管理,隻要弄清楚

JWT

的資料結構以及它簽發和驗證的過程即可。

一. 

JWT

的資料結構以及簽發過程

一個

JWT

實際上是由三個部分組成:

header(頭部)

payload(載荷)

signature(簽名

)。這三個部分在

JWT

裡面分别對應英文句号分隔出來的三個串:

使用jwt完成sso單點登入

先來看

header

部分的結構以及它的生成方法。

header

部分是由下面格式的json結構生成出來:

使用jwt完成sso單點登入

這個json中的

typ

屬性,用來辨別整個

token

字元串是一個

JWT

字元串;它的

alg

屬性,用來說明這個

JWT

簽發的時候所使用的簽名和摘要算法,常用的值以及對應的算法如下:

使用jwt完成sso單點登入

typ

alg

屬性的全稱其實是

type

algorithm

,分别是類型跟算法的意思。之是以都用三個字母來表示,也是基于

JWT

最終字串大小的考慮,同時也是跟

JWT

這個名稱保持一緻,這樣就都是三個字元了…

typ

alg

JWT

中标準中規定的屬性名稱,雖然在簽發

JWT

的時候,也可以把這兩個名稱換掉,但是如果随意更換了這個名稱,就有可能在

JWT

驗證的時候碰到問題,因為拿到

JWT

的人,預設會根據

typ

alg

去拿

JWT

中的

header

資訊,當你改了名稱之後,顯然别人是拿不到

header

資訊的,他又不知道你把這兩個名字換成了什麼。

JWT

作為标準的意義在于統一各方對同一個事情的處理方式,各個使用方都按它約定好的格式和方法來簽發和驗證

token

,這樣即使運作的平台不一樣,也能夠保證

token

進行正确的傳遞。

一般簽發

JWT

的時候,

header

對應的json結構隻需要

typ

alg

屬性就夠了。

JWT

header

部分是把前面的json結構,經過Base64Url編碼之後生成出來的:

使用jwt完成sso單點登入

(線上base64編碼:http://www1.tc711.com/tool/BASE64.htm)

再來看

payload

部分的結構和生成過程。

payload

部分是由下面類似格式的json結構生成出來:

使用jwt完成sso單點登入

payload

的json結構并不像

header

那麼簡單,

payload

用來承載要傳遞的資料,它的json結構實際上是對

JWT

要傳遞的資料的一組聲明,這些聲明被

JWT

标準稱為

claims

,它的一個“屬性值對”其實就是一個

claim

,每一個

claim

的都代表特定的含義和作用。比如上面結構中的

sub

代表這個

token

的所有人,存儲的是所有人的

ID

name

表示這個所有人的名字;

admin

表示所有人是否管理者的角色。當後面對

JWT

進行驗證的時候,這些

claim

都能發揮特定的作用。

根據

JWT

的标準,這些

claims

可以分為以下三種類型: 

1. 

Reserved claims(保留)

,它的含義就像是程式設計語言的保留字一樣,屬于

JWT

标準裡面規定的一些

claim

JWT

标準裡面定好的

claim

有:

iss(Issuser)

:代表這個JWT的簽發主體; 

sub(Subject)

:代表這個JWT的主體,即它的所有人; 

aud(Audience)

:代表這個JWT的接收對象; 

exp(Expiration time)

:是一個時間戳,代表這個JWT的過期時間; 

nbf(Not Before)

:是一個時間戳,代表這個JWT生效的開始時間,意味着在這個時間之前驗證JWT是會失敗的; 

iat(Issued at)

:是一個時間戳,代表這個JWT的簽發時間; 

jti(JWT ID)

:是JWT的唯一辨別。

  1. Public claims

    ,略(不重要)
  2. Private claims

    ,這個指的就是自定義的

    claim

    。比如前面那個結構舉例中的

    admin

    name

    都屬于自定的

    claim

    。這些

    claim

    JWT

    标準規定的

    claim

    差別在于:

    JWT

    規定的

    claim

    JWT

    的接收方在拿到

    JWT

    之後,都知道怎麼對這些标準的

    claim

    進行驗證;而

    private claims

    不會驗證,除非明确告訴接收方要對這些claim進行驗證以及規則才行。

按照

JWT

标準的說明:保留的

claims

都是可選的,在生成

payload

不強制用上面的那些

claim

,你可以完全按照自己的想法來定義

payload

的結構,不過這樣搞根本沒必要:第一是,如果把

JWT

用于認證, 那麼

JWT

标準内規定的幾個

claim

就足夠用了,甚至隻需要其中一兩個就可以了,假如想往

JWT

裡多存一些使用者業務資訊,比如角色和使用者名等,這倒是用自定義的

claim

來添加;第二是,

JWT

标準裡面針對它自己規定的

claim

都提供了有詳細的驗證規則描述,每個實作庫都會參照這個描述來提供

JWT

的驗證實作,是以如果是自定義的

claim

名稱,那麼你用到的實作庫就不會主動去驗證這些

claim

最後也是把這個json結構做base64url編碼之後,就能生成

payload

部分的串:

使用jwt完成sso單點登入

(線上base64編碼:http://www1.tc711.com/tool/BASE64.htm)

最後看

signature

部分的生成過程。簽名是把

header

payload

對應的json結構進行base64url編碼之後得到的兩個串用英文句點号拼接起來,然後根據

header

裡面

alg

指定的簽名算法生成出來的。算法不同,簽名結果不同,但是不同的算法最終要解決的問題是一樣的。以

alg: HS256

為例來說明前面的簽名如何來得到。按照前面

alg

可用值的說明,HS256其實包含的是兩種算法:HMAC算法和SHA256算法,前者用于生成摘要,後者用于對摘要進行數字簽名。這兩個算法也可以用HMACSHA256來統稱。運用HMACSHA256實作

signature

的算法是:

使用jwt完成sso單點登入

正好找到一個線上工具能夠測試這個簽名算法的結果,比如我們拿前面的

header

payload

串來測試,并把“secret”這個字元串就當成密鑰來測試:

使用jwt完成sso單點登入

(https://1024tools.com/hmac)

最後的結果B其實就是JWT需要的signature。不過對比我在介紹JWT的開始部分給出的JWT的舉例:

使用jwt完成sso單點登入

會發現通過線上工具生成的

header

payload

都與這個舉例中的對應部分相同,但是通過線上工具生成的

signature

與上面圖中

的signature

有細微差別,在于最後是否有“=”字元。這個差別産生的原因在于上圖中的

JWT

是通過

JWT

的實作庫簽發的

JWT

,這些實作庫最後編碼的時候都用的是base64url編碼,而前面那些線上工具都是bas64編碼,這兩種編碼方式不完全相同,導緻編碼結果有差別。

以上就是一個

JWT

包含的全部内容以及它的簽發過程。接下來看看該如何去驗證一個

JWT

是否為一個有效的

JWT

二.

JWT

的驗證過程

這個部分介紹

JWT

的驗證規則,主要包括簽名驗證和

payload

裡面各個标準

claim

的驗證邏輯介紹。隻有驗證成功的

JWT

,才能當做有效的憑證來使用。

先說簽名驗證。當接收方接收到一個

JWT

的時候,首先要對這個

JWT

的完整性進行驗證,這個就是簽名認證。它驗證的方法其實很簡單,隻要把

header

做base64url解碼,就能知道

JWT

用的什麼算法做的簽名,然後用這個算法,再次用同樣的邏輯對

header

payload

做一次簽名,并比較這個簽名是否與

JWT

本身包含的第三個部分的串是否完全相同,隻要不同,就可以認為這個

JWT

是一個被篡改過的串,自然就屬于驗證失敗了。接收方生成簽名的時候必須使用跟

JWT

發送方相同的密鑰,意味着要做好密鑰的安全傳遞或共享。

再來看

payload

claim

驗證,拿前面标準的

claim

來一一說明:

iss(Issuser)

:如果簽發的時候這個

claim

的值是“a.com”,驗證的時候如果這個

claim

的值不是“a.com”就屬于驗證失敗; 

sub(Subject)

:如果簽發的時候這個

claim

的值是“liuyunzhuge”,驗證的時候如果這個

claim

的值不是“liuyunzhuge”就屬于驗證失敗; 

(Audience)

:如果簽發的時候這個

claim

的值是“[‘b.com’,’c.com’]”,驗證的時候這個

claim

的值至少要包含b.com,c.com的其中一個才能驗證通過; 

exp(Expiration time)

:如果驗證的時候超過了這個

claim

指定的時間,就屬于驗證失敗; 

nbf(Not Before)

:如果驗證的時候小于這個

claim

指定的時間,就屬于驗證失敗; 

iat(Issued at)

:它可以用來做一些maxAge之類的驗證,假如驗證時間與這個

claim

指定的時間相差的時間大于通過maxAge指定的一個值,就屬于驗證失敗; 

jti(JWT ID)

:如果簽發的時候這個

claim

的值是“1”,驗證的時候如果這個

claim

的值不是“1”就屬于驗證失敗; 

需要注意的是,在驗證一個

JWT

的時候,簽名認證是每個實作庫都會自動做的,但是

payload

的認證是由使用者來決定的。因為

JWT

裡面可能不會包含任何一個标準的

claim

,是以它不會自動去驗證這些

claim

以登入認證來說,在簽發

JWT

的時候,完全可以隻用

sub

exp

兩個

claim

,用

sub

存儲使用者的

id

,用

exp

存儲它本次登入之後的過期時間,然後在驗證的時候僅驗證

exp

這個

claim

,以實作會話的有效期管理。

JWT SSO

場景一:使用者發起對業務系統的第一次通路,假設他第一次通路的是系統A的some/page這個頁面,它最終成功通路到這個頁面的過程是:

使用jwt完成sso單點登入

在這個過程裡面,我認為了解的關鍵點在于:

  1. 它用到了兩個

    cookie

    (

    jwt

    sid

    )和三次重定向來完成會話的建立和會話的傳遞;
  2. jwt

    cookie

    是寫在systemA.com這個域下的,是以每次重定向到systemA.com的時候,

    jwt

    這個

    cookie

    隻要有就會帶過去;
  3. sid

    cookie

    是寫在cas.com這個域下的,是以每次重定向到cas.com的時候,

    sid

    這個

    cookie

    隻要有就會帶過去;
  4. 在驗證

    jwt

    的時候,如何知道目前使用者已經建立了sso的會話? 

    因為

    jwt

    payload

    裡面存儲了之前建立的sso會話的

    sessionid

    ,是以當cas拿到

    jwt

    ,就相當于拿到了

    sessionid

    ,然後用這個

    sessionid

    去判斷有沒有的對應的

    session

    對象即可。

還要注意的是:CAS服務裡面的

session

屬于服務端建立的對象,是以要考慮

sessionid

唯一性以及

session

共享(假如CAS采用叢集部署的話)的問題。

sessionid

的唯一性可以通過使用者名密碼加随機數然後用hash算法如md5簡單處理;

session

共享,可以用

memcached

或者

redis

這種專門的支援叢集部署的緩存伺服器管理

session

來處理。

由于服務端

session

具有生命周期的特點,到期需自動銷毀,是以不要自己去寫

session

的管理,免得引發其它問題,到github裡找開源的緩存管理中間件來處理即可。存儲

session

對象的時候,隻要用

sessionid

作為key,

session

對象本身作為

value

,存入緩存即可。

session

對象裡面除了

sessionid

,還可以存放登入之後擷取的使用者資訊等業務資料,友善業務系統調用的時候,從

session

裡面傳回會話資料。

場景二:使用者登入之後,繼續通路系統A的其它頁面,如some/page2,它的處理過程是:

使用jwt完成sso單點登入

從這一步可以看出,即使登入之後,也要每次跟CAS校驗

jwt

的有效性以及會話的有效性,其實

jwt

的有效性也可以放在業務系統裡面處理的,但是會話的有效性就必須到CAS那邊才能完成了。當CAS拿到

jwt

裡面的

sessionid

之後,就能到

session

緩存伺服器裡面去驗證該

sessionid

對應的

session

對象是否存在,不存在,就說明會話已經銷毀了(退出)。

場景三:使用者登入了系統A之後,再去通路其他系統如系統B的資源,比如系統B的some/page,它最終能通路到系統B的some/page的流程是:

使用jwt完成sso單點登入

這個過程的關鍵在于第一次重定向的時候,它會把

sid

這個

cookie

帶回給CAS伺服器,是以CAS伺服器能夠判斷出會話是否已經建立,如果已經建立就跳過登入頁的邏輯。

場景四:使用者繼續通路系統B的其它資源,如系統B的some/page2:

使用jwt完成sso單點登入

這個場景的邏輯跟場景二完全一緻。

場景五:登出,假如它從系統B發起退出,最終的流程是:

使用jwt完成sso單點登入

最重要的是要清除

sid

cookie

jwt

cookie

可能業務系統都有建立,是以不可能在退出的時候還挨個去清除那些系統的

cookie

,隻要

sid

一清除,那麼即使那些

jwt

cookie

在下次通路的時候還會被傳遞到業務系統的服務端,由于

jwt

裡面的

sid

已經無效,是以最後還是會被重定向到CAS登入頁進行處理。

方案總結 

以上方案兩個關鍵的前提:

  1. 整個會話管理其實還是基于服務端的

    session

    來做的,隻不過這個

    session

    隻存在于CAS服務裡面;
  2. CAS之是以信任業務系統的

    jwt

    ,是因為這個

    jwt

    是CAS簽發的,理論上隻要認證通過,就可以認為這個

    jwt

    是合法的。

jwt

本身是不可僞造,不可篡改的,但是不代表非法使用者冒充正常用法發起請求,是以正常的幾個安全政策在實際項目中都應該使用:

  1. 使用https
  2. 使用http-only的

    cookie

    ,針對

    sid

    jwt

  3. 管理好密鑰
  4. 防範CSRF攻擊。

尤其是CSRF攻擊形式,很多都是鑽代碼的漏洞發生的,是以一旦出現CSRF漏洞,并且被人利用,那麼别人就能用獲得的

jwt

,冒充正常使用者通路所有業務系統,這個安全問題的後果還是很嚴重的。考慮到這一點,為了在即使有漏洞的情況将損害減至最小,可以在

jwt

裡面加入一個系統辨別,添加一個驗證,隻有傳過來的

jwt

内的系統辨別與發起

jwt

驗證請求的服務一緻的情況下,才允許驗證通過。這樣的話,一個非法使用者拿到某個系統的

jwt

,就不能用來通路其它業務系統了。

在業務系統跟CAS發起attach/validate請求的時候,也可以在CAS端做些處理,因為這個請求,在一次SSO過程中,一個系統隻應該發一次,是以隻要之前已經給這個系統簽發過jwt了,那麼後續 同一系統的attach/validate請求都可以忽略掉。

總的來說,這個方案的好處有:

  1. 完全分布式,跨平台,CAS以及業務系統均可采用不同的語言來開發;
  2. 業務系統如系統A和系統B,可實作服務端無狀态
  3. 假如是自己來實作,那麼可以輕易的在CAS裡面內建使用者注冊服務以及第三方登入服務,如微信登入等。

它的缺陷是:

  1. 第一次登入某個系統,需要三次重定向;
  2. 登入後的後續請求,每次都需要跟CAS進行會話驗證,是以CAS的性能負載會比較大
  3. 登陸後的後續請求,每次都跟CAS互動,也會增加請求響應時間,影響使用者體驗。

轉載自: 

3種web會話管理的方式 

看圖了解JWT如何用于單點登入

參考文獻:

https://blog.csdn.net/qq_38401919/article/details/80535258

繼續閱讀