溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

springboot中怎么利用JWT實(shí)現(xiàn)單點(diǎn)登錄

發(fā)布時(shí)間:2021-07-24 15:14:02 來(lái)源:億速云 閱讀:196 作者:Leah 欄目:編程語(yǔ)言

本篇文章為大家展示了springboot中怎么利用JWT實(shí)現(xiàn)單點(diǎn)登錄,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。

SSO 介紹  SSO 的幾種實(shí)現(xiàn)方式對(duì)比  基于 JWT 的 spring boot 單點(diǎn)登錄實(shí)戰(zhàn)

注意:

SSO 這個(gè)概念已經(jīng)出現(xiàn)很久很久了,目前各種平臺(tái)都有非常成熟的實(shí)現(xiàn),比如OpenSSO,OpenAM,Kerberos,CAS等,當(dāng)然很多時(shí)候成熟意味著復(fù)雜。本文不討論那些成熟方案的使用,也不考慮 SSO 在 CS 應(yīng)用中的使用。

什么是 SSO

單點(diǎn)點(diǎn)說(shuō)就是:一次登錄后可免登陸訪問(wèn)其他的可信平臺(tái)。比如我們登錄淘寶網(wǎng)后,再打開天貓首頁(yè)可以發(fā)現(xiàn)已經(jīng)是登錄狀態(tài)了。SSO 是一種比較流行的服務(wù)于企業(yè)業(yè)務(wù)整合的一種解決方案。

如何實(shí)現(xiàn) SSO

我們都知道目前的 http 協(xié)議是無(wú)狀態(tài)的,也就是第一次請(qǐng)求和第二次請(qǐng)求是完全獨(dú)立,不相關(guān)的,但現(xiàn)實(shí)中我們的業(yè)務(wù)邏輯都是有狀態(tài)的,這樣就引入了 cookie-session 的機(jī)制來(lái)維護(hù)狀態(tài),瀏覽器端存儲(chǔ)一個(gè) sessionId,后臺(tái)存儲(chǔ)跟該 sessionId 相關(guān)的數(shù)據(jù)。每次向后臺(tái)發(fā)起請(qǐng)求時(shí)都攜帶此 sessionId 就能維持狀態(tài)了。然后就有了 cookie,瀏覽器在發(fā)送請(qǐng)求時(shí)自動(dòng)將 cookie 中的數(shù)據(jù)放到請(qǐng)求中,發(fā)給服務(wù)端,無(wú)需手動(dòng)設(shè)置。

然后我們可以考慮考慮實(shí)現(xiàn) SSO 的核心是什么?答案就是如何讓一個(gè)平臺(tái) A 登錄后,其他的平臺(tái)也能獲取到平臺(tái) A 的登錄信息(在 cookie-session 機(jī)制中就是 sessionId)。

方案一 共享 cookie

基于 cookie-session 機(jī)制的系統(tǒng)中,登錄系統(tǒng)后會(huì)返回一個(gè) sessionId 存儲(chǔ)在 cookie 中,如果我們能夠讓另外一個(gè)系統(tǒng)也能獲取到這個(gè) cookie,不就獲取到憑證信息了,無(wú)需再次登錄。剛好瀏覽器的 cookie 可以實(shí)現(xiàn)這樣的效果(詳見web 跨域及 cookie 學(xué)習(xí))。

cookie 允許同域名(或者父子域名)的不同端口中共享 cookie,這點(diǎn)和 http 的同域策略不一樣(http 請(qǐng)求只要協(xié)議、域名、端口不完全相同便認(rèn)為跨域)。因此只需將多個(gè)應(yīng)用前臺(tái)頁(yè)面部署到相同的域名(或者父子域名),然后共享 session 便能夠?qū)崿F(xiàn)單點(diǎn)登錄。架構(gòu)如下:

上面方案顯而易見的限制就是不僅前臺(tái)頁(yè)面需要共享 cookie,后臺(tái)也需要共享 session(可以用jwt來(lái)干掉 session,但是又會(huì)引入新的問(wèn)題,這里不展開).這個(gè)方案太簡(jiǎn)單了,不作進(jìn)一步說(shuō)明。

方案二 基于回調(diào)實(shí)現(xiàn)

通過(guò)上文可以知道,要實(shí)現(xiàn)單點(diǎn)登錄只需將用戶的身份憑證共享給各個(gè)系統(tǒng),讓后臺(tái)知道現(xiàn)在是誰(shuí)在訪問(wèn)。就能實(shí)現(xiàn)一次登錄,到處訪問(wèn)的效果,實(shí)在是非常方便的。在 session 機(jī)制中是共享 sessionId,然后多個(gè)后臺(tái)使用同一個(gè) session 源即可。這里我們用一種新的基于 JWT 的 token 方式來(lái)實(shí)現(xiàn),不了解 JWT 的可以看這篇:java-jwt 生成與校驗(yàn),簡(jiǎn)單來(lái)說(shuō) jwt 可以攜帶無(wú)法篡改的信息(一段篡改就會(huì)校驗(yàn)失敗),所以我們可以將用戶 id 等非敏感信息直接放到 jwt 中,干掉了后臺(tái)的 session。然后我們要做的就是將 jwt 共享給各個(gè)平臺(tái)頁(yè)面即可。系統(tǒng)架構(gòu)如下:

此架構(gòu)中,業(yè)務(wù)系統(tǒng) A 和業(yè)務(wù)系統(tǒng) B 之間不需要有任何聯(lián)系,他們都只和 SSO 認(rèn)證平臺(tái)打交道,因此可以任意部署,沒(méi)有同域的限制。你可能就要問(wèn)了這樣要怎么共享身份憑證(也就是 jwt 字符串)?這里就要通過(guò) url 參數(shù)來(lái)進(jìn)行騷操作了。

文字總結(jié)來(lái)說(shuō)是這樣的:jwt 存到認(rèn)證平臺(tái)前端的 localStore(不一定是 localStore,cookie,sessionStore 都可以),然后業(yè)務(wù)平臺(tái)攜帶自己的回調(diào)地址跳轉(zhuǎn)到認(rèn)證中心的前臺(tái),認(rèn)證中心的前臺(tái)再將 ujwt 作為 url 參數(shù),跳回到那個(gè)回調(diào)地址上,這樣就完成了 jwt 的共享。

文字很可能看不懂,下面是整個(gè)過(guò)程的路程圖:

相信通過(guò)上面的流程圖你應(yīng)該能大概看明白,jwt 是如何共享了的吧,還看不懂的繼續(xù)看下來(lái),下面上一個(gè) spring boot 實(shí)現(xiàn)的簡(jiǎn)易 SSO 認(rèn)證。主要有兩個(gè)系統(tǒng):SSO 認(rèn)證中心,系統(tǒng) A(系統(tǒng) A 換不同端口運(yùn)行就是系統(tǒng) A、B、C、D 了).

實(shí)戰(zhàn)

實(shí)現(xiàn) SSO 認(rèn)證中心

spring boot 框架先搭起來(lái),由于是簡(jiǎn)易項(xiàng)目,除 spring boot web 基本依賴,只需要如下的額外依賴:

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.4</version></dependency><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.7.0</version></dependency>

完整的 POM 文件,請(qǐng)到 github 上查看.

后臺(tái)實(shí)現(xiàn)

后臺(tái)做的事情并不多,只有以下 5 個(gè)方法:

/login : 登錄成功后簽發(fā)一個(gè) jwt token

在 demo 中只是簡(jiǎn)單對(duì)比用戶名密碼如果是一樣的認(rèn)為登錄成功,返回 token

/checkJwt : 檢查 jwt 的有效性

檢查傳來(lái)的 jwt-token 是否有效,返回失效的 jwt 列表

/refreshjwt : 刷新 jwt

判斷該 jwt 是否快要過(guò)期,如果快要過(guò)期,生成一個(gè)新的 jwt 返回

/inValid : 讓某個(gè) jwt 失效

jwt 如何失效一直是一個(gè)比較麻煩的問(wèn)題,各有利弊。本例中采用的是為每個(gè) jwt 生成一個(gè)隨機(jī)的秘鑰 secret,將 jwt–secret 保存到 redis 中,想要讓某個(gè) jwt 失效,只需將該記錄在 redis 中刪除即可(這樣在解密時(shí)便無(wú)法獲取到 secret)。但是這樣讓無(wú)狀態(tài)的認(rèn)證機(jī)制變成有狀態(tài)了(記錄了 jwt 和 secret 的對(duì)應(yīng)關(guān)系)。

總結(jié)來(lái)說(shuō) SSO 后臺(tái)主要只做了兩件事:驗(yàn)證用戶名密碼返回 jwt;驗(yàn)證 jwt 是否合法。具體代碼查看 github 上 sso 目錄下的代碼。

前臺(tái)實(shí)現(xiàn)

前臺(tái)的邏輯較為復(fù)雜,不是那么容易理解,不明白的多看幾遍上面的流程圖。

再次回到 SSO 的重點(diǎn):分享登錄狀態(tài)。要如何在前臺(tái)將登錄狀態(tài)(在這里就是 jwt 字符串)分享出去呢?由于瀏覽器的限制,除了 cookie 外沒(méi)有直接共享數(shù)據(jù)的辦法。既然沒(méi)有直接共享,那肯定是有間接的辦法的!

這個(gè)辦法就是回調(diào)。系統(tǒng) A 的前臺(tái)在跳轉(zhuǎn)到 SSO 的前臺(tái)時(shí),將當(dāng)前路徑作為 url 參數(shù)傳遞給 sso 前臺(tái),sso 前臺(tái)在獲取到 jwt 后,再跳轉(zhuǎn)到系統(tǒng) A 傳過(guò)來(lái)的 url 路徑上,并帶上 jwt 作為 url 參數(shù)。這就完成了 jwt 的一次共享,從 sso 共享到系統(tǒng) A。

打個(gè)比方:你點(diǎn)了個(gè)外賣,別人要怎么把外賣給你呢?顯然你會(huì)留下的地址,讓別人帶上飯送到這個(gè)地址,然后你就能享用美食了。這和 jwt 的傳遞非常相識(shí)了。

系統(tǒng) A 說(shuō):我要 jwt,快把它送到http://localhost:8081/test1/這個(gè)地址上。

SSO 說(shuō):好嘞,這個(gè)地址是合法的可以送 jwt 過(guò)去,這就跳轉(zhuǎn)過(guò)去:http://localhost:8081/test1/?jwt=abcdefj.asdf.asdfasf

系統(tǒng) A 說(shuō):不錯(cuò)不錯(cuò),真香。

要注意這里有個(gè)坑就是:如果另外一個(gè)惡意系統(tǒng) C 安裝相同的格式跳轉(zhuǎn)到 SSO,想要獲取 jwt,這顯然是不應(yīng)該給它的。所以在回跳回去的時(shí)候要判斷一下這個(gè)回調(diào)地址是不是合法的,能不能給 jwt 給它,可以向后臺(tái)請(qǐng)求判斷也可以在 sso 前臺(tái)直接寫死合法的地址。在 demo 是沒(méi)有這個(gè)判斷過(guò)程的。

實(shí)現(xiàn)業(yè)務(wù)系統(tǒng)

業(yè)務(wù)系統(tǒng)代碼非常簡(jiǎn)單,主要是用了一個(gè)攔截器,攔截 http 請(qǐng)求,提取出 token 向 sso 認(rèn)證中心驗(yàn)證 token 是否有效,有效放行,否則返回錯(cuò)誤給前端。太簡(jiǎn)單也不貼代碼了,到 github 上看看就明白了。

效果

上面說(shuō)了一大串都是原理了,其實(shí)這個(gè)難也就難在原理部分,代碼實(shí)現(xiàn)并沒(méi)有那么復(fù)雜。這里就不貼代碼了,有需要直接到 github 上看。

這里上幾個(gè)效果圖:

系統(tǒng) A 首次登陸系統(tǒng)

可以看到首次登陸是需要跳到sso 認(rèn)證中心輸入用戶名密碼進(jìn)行登陸驗(yàn)證的。登陸成功回跳后接口請(qǐng)求成功。

將 A 的啟動(dòng)端口改為 8082 后再次啟動(dòng),當(dāng)作系統(tǒng) B

可以看到這次是無(wú)需登陸的,跳到認(rèn)證中心后就馬上跳回了,如果去掉 alert 一般是看不出跳轉(zhuǎn)過(guò)程的。

最后在任意一個(gè)系統(tǒng)注銷,都會(huì)讓所有的系統(tǒng)推出登陸。

可以看到,在系統(tǒng) A 登錄系統(tǒng)后,系統(tǒng) B,系統(tǒng) C 都不再需要輸入用戶名密碼進(jìn)行登錄。如果速度足夠快甚至都注意不到調(diào)到 SSO 再跳回來(lái)的過(guò)程。

上述內(nèi)容就是springboot中怎么利用JWT實(shí)現(xiàn)單點(diǎn)登錄,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI