SSO CAS

主要介紹CAS SSO的認(rèn)證流程。有關(guān)這方面的內(nèi)容再網(wǎng)上也有很多資料,寫這篇總結(jié)目的一來(lái)是自己在理解這塊內(nèi)容的時(shí)候覺(jué)得專業(yè)術(shù)語(yǔ)有點(diǎn)多,理來(lái)理去有點(diǎn)繞,想通過(guò)總結(jié)來(lái)加強(qiáng)自己對(duì)這一塊內(nèi)容的理解;其次,網(wǎng)上的資料雖然很多,但是很多都不是很全面,而這篇總結(jié)剛好可以在前人的基礎(chǔ)上進(jìn)行過(guò)總結(jié),結(jié)合網(wǎng)上的一些資料,再加上自己的 一些理解,應(yīng)該可以更快的掌握這一塊內(nèi)容。這篇總結(jié)主要是一些理論層面的內(nèi)容,請(qǐng)看其它兩篇文章。

相關(guān)鏈接:
http://blog.csdn.net/gzseehope/article/details/72914188

http://blog.csdn.net/tyt_venice/article/details/56675186

http://blog.csdn.net/javaloveiphone/article/details/52439613

http://www.imooc.com/article/3558

運(yùn)行原理

基本概念

  • CAS ( Central Authentication Service ) 是 Yale 大學(xué)發(fā)起的一個(gè)企業(yè)級(jí)的、開源的項(xiàng)目,旨在為 Web 應(yīng)用系統(tǒng)提供一種可靠的單點(diǎn)登錄解決方法(屬于 Web SSO)。CAS 開始于 2001 年, 并在 2004 年 12 月正式成為 JA-SIG 的一個(gè)項(xiàng)目。
  • SSO 單點(diǎn)登錄(Single Sign-On)是目前比較流行的服務(wù)于企業(yè)業(yè)務(wù)整合的解決方案之一, SSO 使得在多個(gè)應(yīng)用系統(tǒng)中,用戶只需要 登錄一次 就可以訪問(wèn)所有相互信任的應(yīng)用系統(tǒng)。
  • CAS 包括兩部分: CAS Server 和 CAS Client 。CAS Server 負(fù)責(zé)完成對(duì)用戶的認(rèn)證工作 , 需要獨(dú)立部署 , CAS Server 會(huì)處理用戶名 / 密碼等憑證(Credentials) 。CAS Client與受保護(hù)的客戶端應(yīng)用部署在一起,以 Filter 方式保護(hù)受保護(hù)的資源。負(fù)責(zé)處理對(duì)客戶端受保護(hù)資源的訪問(wèn)請(qǐng)求,需要對(duì)請(qǐng)求方進(jìn)行身份認(rèn)證時(shí),重定向到 CAS Server 進(jìn)行認(rèn)證。(原則上,客戶端應(yīng)用不再接受任何的用戶名密碼等 Credentials)。

CAS基礎(chǔ)模式

先看看網(wǎng)上的一個(gè)CAS基本協(xié)議過(guò)程:

image.png
  1. 訪問(wèn)服務(wù):SSO 客戶端發(fā)送請(qǐng)求訪問(wèn)應(yīng)用系統(tǒng)提供的服務(wù)資源。
  2. 定向認(rèn)證:SSO 客戶端會(huì)重定向用戶請(qǐng)求到 SSO 服務(wù)器。
  3. 用戶認(rèn)證:用戶身份認(rèn)證。
  4. 發(fā)放票據(jù): SSO 服務(wù)器會(huì)產(chǎn)生一個(gè)隨機(jī)的 Service Ticket 。
  5. 驗(yàn)證票據(jù): SSO 服務(wù)器驗(yàn)證票據(jù) ST 的合法性,驗(yàn)證通過(guò)后,允許客戶端訪問(wèn)服務(wù)。
  6. 傳輸用戶信息: SSO 服務(wù)器驗(yàn)證票據(jù)通過(guò)后,傳輸用戶認(rèn)證結(jié)果信息給客戶端。

CAS Client 與受保護(hù)的客戶端應(yīng)用部署在一起,以 Filter 方式保護(hù) Web 應(yīng)用的受保護(hù)資源,過(guò)濾從客戶端過(guò)來(lái)的每一個(gè) Web 請(qǐng)求,同時(shí), CAS Client 會(huì)分析 HTTP 請(qǐng)求中是否包含請(qǐng)求 Service Ticket( ST 上圖中的 Ticket) ,如果沒(méi)有,則說(shuō)明該用戶是沒(méi)有經(jīng)過(guò)認(rèn)證的;于是 CAS Client 會(huì)重定向用戶請(qǐng)求到 CAS Server ( Step 2 ),并傳遞 Service (要訪問(wèn)的目的資源地址)。 Step 3 是用戶認(rèn)證過(guò)程,如果用戶提供了正確的 Credentials , CAS Server 隨機(jī)產(chǎn)生一個(gè)相當(dāng)長(zhǎng)度、唯一、不可偽造的 Service Ticket ,并緩存以待將來(lái)驗(yàn)證,并且重定向用戶到 Service 所在地址(附帶剛才產(chǎn)生的 Service Ticket ) , 并為客戶端瀏覽器設(shè)置一個(gè) Ticket Granted Cookie ( TGC ) ; CAS Client 在拿到 Service 和新產(chǎn)生的 Ticket 過(guò)后,在 Step 5 和 Step6 中與 CAS Server 進(jìn)行身份核實(shí),以確保 Service Ticket 的合法性。在該協(xié)議中,所有與 CAS Server 的交互均采用 SSL 協(xié)議,以確保 ST 和 TGC 的安全性。協(xié)議工作過(guò)程中會(huì)有 2 次重定向 的過(guò)程。但是 CAS Client 與 CAS Server 之間進(jìn)行 Ticket 驗(yàn)證的過(guò)程對(duì)于用戶是透明的(使用 HttpsURLConnection )。

應(yīng)用系統(tǒng)將登錄請(qǐng)求轉(zhuǎn)給認(rèn)證中心,這個(gè)很好解決,我們一個(gè)HTTP重定向即可實(shí)現(xiàn)。現(xiàn)在的問(wèn)題是,用戶在認(rèn)證中心登錄后,認(rèn)證中心如何將消息轉(zhuǎn)回給該系統(tǒng)?這是在單web系統(tǒng)中不存在的問(wèn)題。我們知道HTTP協(xié)議傳遞消息只能通過(guò)請(qǐng)求參數(shù)方式或cookie方式,cookie跨域問(wèn)題不能解決,我們只能通過(guò)URL請(qǐng)求參數(shù)。我們可以將認(rèn)證通過(guò)消息做成一個(gè)令牌(token)再利用HTTP重定向傳遞給應(yīng)用系統(tǒng)。但現(xiàn)在的關(guān)鍵是:該系統(tǒng)如何判斷這個(gè)令牌的真?zhèn)??如果判斷這個(gè)令牌確實(shí)是由認(rèn)證中心發(fā)出的,且是有效的?我們還需要應(yīng)用系統(tǒng)和認(rèn)證中心之間再來(lái)個(gè)直接通信,來(lái)驗(yàn)證這個(gè)令牌確實(shí)是認(rèn)證中心發(fā)出的,且是有效的。由于應(yīng)用系統(tǒng)和認(rèn)證中心是屬于服務(wù)端之間的通信,不經(jīng)過(guò)用戶瀏覽器,相對(duì)是安全的。

假如現(xiàn)在應(yīng)用集群中又兩個(gè)系統(tǒng)A、B。當(dāng)客戶首次登錄A系統(tǒng)的時(shí)候,流程如下:

  1. 用戶瀏覽器訪問(wèn)系統(tǒng)A需登錄受限資源。
  2. 系統(tǒng)A發(fā)現(xiàn)該請(qǐng)求需要登錄,將請(qǐng)求重定向到認(rèn)證中心,進(jìn)行登錄。
  3. 認(rèn)證中心呈現(xiàn)登錄頁(yè)面,用戶登錄,登錄成功后,認(rèn)證中心重定向請(qǐng)求到系統(tǒng)A,并附上認(rèn)證通過(guò)令牌。
  4. 系統(tǒng)A與認(rèn)證中心通信,驗(yàn)證令牌有效,證明用戶已登錄。
  5. 系統(tǒng)A將受限資源返給用戶。
image.png

已登錄用戶首次訪問(wèn)應(yīng)用群中系統(tǒng)B時(shí):

  1. 瀏覽器訪問(wèn)另一應(yīng)用B需登錄受限資源。
  2. 系統(tǒng)B發(fā)現(xiàn)該請(qǐng)求需要登錄,將請(qǐng)求重定向到認(rèn)證中心,進(jìn)行登錄。
  3. 認(rèn)證中心發(fā)現(xiàn)已經(jīng)登錄,即重定向請(qǐng)求響應(yīng)到系統(tǒng)B,附帶上認(rèn)證令牌。
  4. 系統(tǒng)B與認(rèn)證中心通信,驗(yàn)證令牌有效,證明用戶已登錄。
  5. 系統(tǒng)B將受限資源返回給客戶端。
image.png
登錄狀態(tài)判斷

用戶到認(rèn)證中心登錄后,用戶和認(rèn)證中心之間建立起了會(huì)話,我們把這個(gè)會(huì)話稱為全局會(huì)話。當(dāng)用戶后續(xù)訪問(wèn)系統(tǒng)應(yīng)用時(shí),我們不可能每次應(yīng)用請(qǐng)求都到認(rèn)證中心去判定是否登錄,這樣效率非常低下,這也是單Web應(yīng)用不需要考慮的。我們可以在系統(tǒng)應(yīng)用和用戶瀏覽器之間建立起局部會(huì)話,局部會(huì)話保持了客戶端與該系統(tǒng)應(yīng)用的登錄狀態(tài),局部會(huì)話依附于全局會(huì)話存在,全局會(huì)話消失,局部會(huì)話必須消失。用戶訪問(wèn)應(yīng)用時(shí),首先判斷局部會(huì)話是否存在,如存在,即認(rèn)為是登錄狀態(tài),無(wú)需再到認(rèn)證中心去判斷。如不存在,就重定向到認(rèn)證中心判斷全局會(huì)話是否存在,如存在,按1提到的方式通知該應(yīng)用,該應(yīng)用與客戶端就建立起它們之間局部會(huì)話,下次請(qǐng)求該應(yīng)用,就不去認(rèn)證中心驗(yàn)證了。

登出

用戶在一個(gè)系統(tǒng)登出了,訪問(wèn)其它子系統(tǒng),也應(yīng)該是登出狀態(tài)。要想做到這一點(diǎn),應(yīng)用除結(jié)束本地局部會(huì)話外,還應(yīng)該通知認(rèn)證中心該用戶登出。認(rèn)證中心接到登出通知,即可結(jié)束全局會(huì)話,同時(shí)需要通知所有已建立局部會(huì)話的子系統(tǒng),將它們的局部會(huì)話銷毀。這樣,用戶訪問(wèn)其它應(yīng)用時(shí),都顯示已登出狀態(tài)。
整個(gè)登出流程如下:
1.客戶端向應(yīng)用A發(fā)送登出Logout請(qǐng)求。
2.應(yīng)用A取消本地會(huì)話,同時(shí)通知認(rèn)證中心,用戶已登出。
3.應(yīng)用A返回客戶端登出請(qǐng)求。
4.認(rèn)證中心通知所有用戶登錄訪問(wèn)的應(yīng)用,用戶已登出。

基礎(chǔ)模式總結(jié)

雖然很多東西都是從網(wǎng)上查過(guò)來(lái)的,但是對(duì)我們理解這塊的內(nèi)容卻非常有幫助。當(dāng)然,通過(guò)上面的內(nèi)容,基本上額可以了解CAS SSO的基本原理,但還是有一些不明白的地方,因此還是有必要用自己的話總結(jié)一遍。
幾個(gè)注意點(diǎn):

  • 用戶認(rèn)證操作是 完全交給認(rèn)證中心的。比如用戶在瀏覽器上輸入的用戶名、密碼,這些信息按理來(lái)說(shuō)是完全可以不和你的應(yīng)用系統(tǒng)打交道的,因?yàn)檎J(rèn)證操作完全是由認(rèn)證中心(也就是 CAS Server)來(lái)處理的。
  • 全局會(huì)話是是由用戶和認(rèn)證中心建立的,這個(gè)全局會(huì)話就是TGT(Ticket Granting Ticket),或者說(shuō):登錄成功后,認(rèn)證中心會(huì)產(chǎn)生一個(gè)票據(jù)叫TGT(Ticket Granting Ticket),TGT即代表了用戶與認(rèn)證中心直接的全局會(huì)話,TGT存在,表明該用戶處于登錄狀態(tài)。TGT位于CAS服務(wù)器端,TGT并沒(méi)有放在Session中,也就是說(shuō),CAS全局會(huì)話的實(shí)現(xiàn)并沒(méi)有直接使用Session機(jī)制,而是利用了Cookie自己實(shí)現(xiàn)的,這個(gè)Cookie叫做TGC(Ticket Granting Cookie),它存放了TGT的id,保存在用戶瀏覽器上,CAS Server實(shí)現(xiàn)了TGT。
  • 局部會(huì)話是由瀏覽器和應(yīng)用系統(tǒng)之間建立的。并且局部會(huì)話必須依賴于全局會(huì)話。創(chuàng)建局部會(huì)話,相當(dāng)于是在瀏覽器和因夠用系統(tǒng)之間創(chuàng)建了一個(gè)session。一般是在用戶首次登錄的時(shí)候創(chuàng)建的(是這樣嗎?)。

假如現(xiàn)在有A、B兩個(gè)系統(tǒng)屬于同一應(yīng)用群,當(dāng)用戶向系統(tǒng)A發(fā)送一個(gè)請(qǐng)求的時(shí)候,大概是這樣一個(gè)過(guò)程:
1、 用戶通過(guò)瀏覽器訪問(wèn)系統(tǒng)A,系統(tǒng)A(也可以稱為CAS客戶端)去Cookie中拿JSESSION,即在Cookie中維護(hù)的當(dāng)前回話session的id,如果拿到了,說(shuō)明用戶已經(jīng)登錄,這時(shí)候直接返回請(qǐng)求的資源,這里沒(méi)有啥好討論的。如果未拿到,說(shuō)明用戶未登錄,主要討論這一塊內(nèi)容。

2、 如果發(fā)現(xiàn)用戶未登錄。系統(tǒng)A就重定向到認(rèn)證中心(CAS 服務(wù)端),并將當(dāng)前客戶端的地址作為參數(shù)傳遞到認(rèn)證中心(以便于認(rèn)證中心生成ST之后返回當(dāng)前地址),假如系統(tǒng)A的地址為http://a:8080/,CAS認(rèn)證中心的服務(wù)地址為http://cas.server:8080/,那么重點(diǎn)向前后地址變化為:由http://a:8080/http://cas.server:8080/?service=http://a:8080/,由此可知,重點(diǎn)向到認(rèn)證中心,認(rèn)證中心拿到了當(dāng)前訪問(wèn)客戶端的地址。

3、 重定向到認(rèn)證中心后,認(rèn)證中心首先會(huì)去瀏覽器拿全局會(huì)話id(也就是TGT,TGC中存放了TGT的id),如果不存在就進(jìn)入認(rèn)證中心的登錄界面,用戶輸入用戶名、密碼進(jìn)行登錄,登錄成功后,CAS 服務(wù)端創(chuàng)建全局會(huì)話TGT,并且將TGT最為緩存在cookie中(TGC),同時(shí)會(huì)產(chǎn)生一個(gè)隨機(jī)的 Service Ticket (ST),并且重定向到A系統(tǒng),并且攜帶ST,重定向之后的地址變?yōu)椋?a href="http://a:8080/?ticket=ST-XXXX-XXX" target="_blank" rel="nofollow">http://a:8080/?ticket=ST-XXXX-XXX。

4、 系統(tǒng)A通過(guò)地址欄獲取ticket的參數(shù)值ST票據(jù),然后從后臺(tái)將ST發(fā)送給CAS server認(rèn)證中心驗(yàn)證,驗(yàn)證ST有效后,CAS server返回當(dāng)前用戶登錄的相關(guān)信息,系統(tǒng)A接收到返回的用戶信息,并為該用戶創(chuàng)建session會(huì)話(局部會(huì)話),會(huì)話id由cookie維護(hù),來(lái)證明其已登錄。

5、 系統(tǒng)A將資源返回給 瀏覽器。
至此,用戶向系統(tǒng)A發(fā)送一個(gè)請(qǐng)求的流程已經(jīng)完成。這個(gè)時(shí)候,如果用戶向系統(tǒng)A發(fā)送另外一個(gè)請(qǐng)求,因?yàn)橄到y(tǒng)A和瀏覽器之間已經(jīng)創(chuàng)建了一個(gè)局部會(huì)話,因此這時(shí)候會(huì)直接返回資源。

假如還是同一個(gè)用戶,向系統(tǒng)B發(fā)送一個(gè)請(qǐng)求,流程是什么樣的?

1、 在系統(tǒng)A登錄成功后,用戶和認(rèn)證中心之間建立起了全局會(huì)話,這個(gè)全局會(huì)話就是TGT(Ticket Granting Ticket),TGT位于CAS服務(wù)器端,TGT并沒(méi)有放在Session中,也就是說(shuō),CAS全局會(huì)話的實(shí)現(xiàn)并沒(méi)有直接使用Session機(jī)制,而是利用了Cookie自己實(shí)現(xiàn)的,這個(gè)Cookie叫做TGC(Ticket Granting Cookie),它存放了TGT的id,保存在用戶瀏覽器上。用戶發(fā)送登錄系統(tǒng)B的請(qǐng)求,首先會(huì)去Cookie中拿JSESSION,因?yàn)橄到y(tǒng)B并未登錄過(guò),session會(huì)話還未創(chuàng)建,JSESSION的值是拿不到的,然后將請(qǐng)求重定向到CAS認(rèn)證中心,CAS認(rèn)證中心先去用戶瀏覽器中拿TGC的值,也就是全局會(huì)話id,如果存在則代表用戶在認(rèn)證中心已經(jīng)登錄,附帶上認(rèn)證令牌重定向到系統(tǒng)B。如果全局會(huì)話不存在,那這是就好執(zhí)行一次建立全局會(huì)話的過(guò)程。

2、 系統(tǒng)B拿到ST后,也會(huì)在系統(tǒng)B和瀏覽器之間建立一個(gè)局部會(huì)話。

3、 將系統(tǒng)B的資源返回給瀏覽器。

認(rèn)證中心清除當(dāng)前用戶的全局會(huì)話TGT,同時(shí)清掉cookie中TGT的id:TGC;
然后是各個(gè)客戶端系統(tǒng),比如系統(tǒng)A、系統(tǒng)B,清除局部會(huì)話session,同時(shí)清掉cookie中session會(huì)話id:jsession。

CAS代理模式

用網(wǎng)上找到的一些概念:代理模式形式為用戶訪問(wèn)App1,App1又依賴于App2來(lái)獲取一些信息,如:User -->App1 -->App2 。這種情況下,假設(shè)App2也是需要對(duì)User進(jìn)行身份驗(yàn)證才能訪問(wèn),那么,為了不影響用戶體驗(yàn)(過(guò)多的重定向?qū)е耈ser的IE窗口不停地閃動(dòng)),CAS引入了一種Proxy認(rèn)證機(jī)制,即CAS Client可以代理用戶去訪問(wèn)其它Web應(yīng)用。代理的前提是需要CAS Client擁有用戶的身份信息(類似憑據(jù))。之前我們提到的TGC是用戶持有對(duì)自己身份信息的一種憑據(jù),這里的PGT就是CAS Client端持有的對(duì)用戶身份信息的一種憑據(jù)。憑借TGC,User可以免去輸入密碼以獲取訪問(wèn)其它服務(wù)的Service Ticket,所以,這里憑借PGT,Web應(yīng)用可以代理用戶去實(shí)現(xiàn)后端的認(rèn)證,而無(wú)需前端用戶的參與。下面為代理應(yīng)用(helloService)獲取PGT的過(guò)程:(注:PGTURL用于表示一個(gè)Proxy服務(wù),是一個(gè)回調(diào)鏈接;PGT相當(dāng)于代理證;PGTIOU為取代理證的鑰匙,用來(lái)與PGT做關(guān)聯(lián)關(guān)系;)

image.png

CAS Client 在基礎(chǔ)協(xié)議之上,在驗(yàn)證ST時(shí)提供了一個(gè)額外的PGT URL(而且是 SSL 的入口)給CAS Server,使得CAS Server可以通過(guò)PGT URL提供一個(gè)PGT給CAS Client。
CAS Client拿到了PGT(PGTIOU-85…..ti2td),就可以通過(guò)PGT向后端Web應(yīng)用進(jìn)行認(rèn)證。
下面是代理認(rèn)證和提供服務(wù)的過(guò)程:

image.png
與基礎(chǔ)模式的異同

首先要明白一點(diǎn):基礎(chǔ)模式是用戶對(duì)自己信息的一種憑據(jù);而代理模式是CAS Client對(duì)用戶信息的一種憑據(jù)。代理模式認(rèn)證與普通模式的認(rèn)證其實(shí)差別不大,第一步和第二步與基礎(chǔ)模式的第一步和第二步幾乎一樣,唯一不同的是,代理模式用的是PGT而不是TGC,是Proxy Ticket(PT)而不是Service Ticket(ST)。

CAS Server

主要介紹CAS Server的簡(jiǎn)單搭建過(guò)程。感覺(jué)在實(shí)際開發(fā)過(guò)程中,應(yīng)該更多的是處理一個(gè)CAS Client的集成問(wèn)題吧?但也還是簡(jiǎn)單的了解一下CAS Server的搭建過(guò)程吧。

相關(guān)鏈接:
http://www.cnblogs.com/rwxwsblog/p/4954795.html

http://www.itdecent.cn/p/67d10532c5f8

基礎(chǔ)環(huán)境

  • 系統(tǒng):win10
  • JDK: jdk1.8.0_101
  • CAS Server:cas-server-4.0.0-release.zip
    前提條件,JDK和tomcat已經(jīng)配置成功。

生成證書

keytool -genkey -alias castest -keyalg RSA -keystore D:/keys/castest

生成一個(gè)別名為castest的證書。
此處需要特別注意口令(后續(xù)導(dǎo)入導(dǎo)出證書、CAS服務(wù)器端均要用到此口類)和“名字與姓氏”(為CAS跳轉(zhuǎn)域名,否則會(huì)報(bào)錯(cuò))

image.png

導(dǎo)出證書

keytool -export -file F:/keys/castest.crt -alias castest -keystore D:/keys/castest

將證書導(dǎo)入到客戶端JRE

將證書導(dǎo)入到客戶端JRE中(注意、是導(dǎo)入JRE中),如果security中已經(jīng)存在cacerts,需要先將其刪除。
keytool -import -keystore "C:\Program Files\Java\jdk1.8.0_101\jre\lib\security\cacerts" -file D:/keys/castest.crt -alias castest
這里由一個(gè)需要注意的地方,因?yàn)槲业腏DK是安裝在C盤(系統(tǒng)盤),而你往系統(tǒng)盤里面寫入文件是需要權(quán)限的,所以,這條命令可能需要用管理員權(quán)限運(yùn)行。
如果看過(guò)如下錯(cuò)誤,請(qǐng)使用管理員權(quán)限運(yùn)行:

image.png

以管理員權(quán)限運(yùn)行結(jié)果如下:


image.png

配置服務(wù)器端

  1. http://developer.jasig.org/cas/上下載cas服務(wù)器端cas-server-4.0.0-release.zip,在modules目錄下找到cas-server-webapp-4.0.0.war,將其復(fù)制到%TOMCAT_HOME%\webapps下,并將名稱改為cas.war
image.png
  1. 修改%TOMCAT_HOME%\conf\server.xml文件:
image.png
  1. 啟動(dòng)tomcat測(cè)試
    進(jìn)入tomcat根目錄下的bin目錄,執(zhí)行:startup.bat
    提示啟動(dòng)成功,這時(shí)候打開瀏覽器,輸入地址:https://localhost:8443,提示
image.png

點(diǎn)擊繼續(xù)訪問(wèn),可以看到tomcat的主頁(yè):


image.png

說(shuō)明證書安裝成功。

用戶密碼通過(guò)配置文件配置

在瀏覽器輸入地址:https://localhost:8443/cas

這時(shí)瀏覽器會(huì)重定向到https://localhost:8443/cas/login

image.png

這時(shí)候需要我們提供用戶名和密碼,可是用戶名和密碼我們并不知道。不過(guò)它默認(rèn)的用戶名密碼是配置在配置文件中。
進(jìn)入目錄:tomcat根目錄 \webapps\cas\WEB-INF,打deployerConfigContext.xml文件,找到以下內(nèi)容:

image.png

這里的key就是用戶名,value就是密碼,我們也可以對(duì)其自己修改。這時(shí)候回到瀏覽器,輸入用戶名:casuser和密碼:Mellon。提示登錄成功

image.png

至此,cas服務(wù)端配置成功。

用戶密碼和數(shù)據(jù)庫(kù)交互

假如需要和數(shù)據(jù)庫(kù)交互,應(yīng)該如何配置呢?因?yàn)槲冶镜厥褂玫氖莔ysql,所以需要將以下幾個(gè)jar包放到WEB-INF/lib目錄下:
mysql-connector-java-5.1.34.jar
c3p0-0.9.1.1.jar
cas-server-support-jdbc-4.0.0.jar
其中的cas-server-support-jdbc-4.0.0.jar我是直接從module目錄下拷貝過(guò)來(lái)的,我們這里 是直接拷貝到該目錄下,也有其他的方法,因?yàn)閏as server本來(lái)就一個(gè)maven項(xiàng)目,也可以自己修改pom.xml文件,然后重新打包就好了。

image.png

修改配置文件,支持mysql交互。進(jìn)入目錄:tomcat根目錄 \webapps\cas\WEB-INF,打deployerConfigContext.xml文件,找到以下內(nèi)容:

image.png

將這一段修改成以下內(nèi)容:


image.png

然后,在該配置文件中添加兩個(gè)bean配置,如下:


image.png

至此,配置文件已經(jīng)完成,接下來(lái)是測(cè)試。

測(cè)試mysql交互

重啟tomcat。如果這時(shí)候提示你登錄成功,則在瀏覽器地址欄輸入:

https://localhost:8443/cas/logout,這是登出

image.png

然后重新在地址欄輸入:https://localhost:8443/cas/

這時(shí)候會(huì)提示需要重新登錄,這時(shí)候我們不使用配置文件中的用戶名和密碼,而是使用數(shù)據(jù)庫(kù)中的用戶名密碼。為了測(cè)試方便,此處我選擇了一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)進(jìn)行測(cè)試,密碼也沒(méi)有進(jìn)行加密處理:

image.png

可以發(fā)現(xiàn),在 o_user表中,對(duì)應(yīng)了一條 Moxie 和 Admin的記錄,這時(shí)候在登錄界面輸入用戶名Moxie密碼Admin:

image.png

點(diǎn)擊登錄之后,成功跳轉(zhuǎn)到登錄成功界面,說(shuō)明和mysql交互成功。當(dāng)然這里的交互只是最簡(jiǎn)單的交互,還需要慢慢摸索。

CAS Client

主要介紹CAS Client的簡(jiǎn)單搭建過(guò)程,多個(gè)客戶端實(shí)現(xiàn)單點(diǎn)登錄。相關(guān)鏈接:

http://www.cnblogs.com/rwxwsblog/p/4954795.html

http://www.itdecent.cn/p/67d10532c5f8

http://blog.csdn.net/zhmz1326/article/details/52279740

基本環(huán)境

  • 系統(tǒng):win10
  • JDK: jdk1.8.0_101
  • Tomcat:tomcat8
  • CAS Server:cas-server-4.0.0-release.zip

準(zhǔn)備tomcat

為了演示多個(gè)客戶端的單點(diǎn)登錄功能,所以客戶端至少需要兩個(gè)。所以本地只使用2個(gè)tomcat客戶端來(lái)測(cè)試。首先,客戶端應(yīng)用是要和CAS服務(wù)端進(jìn)行交互的,所以這里需要jar文件,放在客戶端應(yīng)用的lib目錄下。分別是:cas-client-core-3.2.1.jar、commons-logging.jar。這里直接使用tomcat默認(rèn)自帶的 webapps\examples 作為演示的簡(jiǎn)單web項(xiàng)目。
目錄結(jié)構(gòu)如下:

image.png

客戶端添加jar包

Tomcat解壓之后,現(xiàn)在還無(wú)法同CAS Server交互,還缺少兩個(gè)jar包,分別是:

cas-client-core-3.2.0.jar、

commons-logging-1.1.jar

可以從:http://developer.jasig.org/cas-clients/下載。(注意,這里版本不對(duì)可能會(huì)出異常,比如我一開始用的是3.33版本,在配置filter之后就發(fā)現(xiàn)不能正常訪問(wèn))。

需要放到客戶端應(yīng)用的lib目錄下面。我這里的目錄分別是:
D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client1\webapps\examples\WEB-INF\lib

D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client2\webapps\examples\WEB-INF\lib

image.png

客戶端添修改端口

因?yàn)槲覀兪窃谕慌_(tái)機(jī)器上運(yùn)行,然后tomcat默認(rèn)的端口是8080,如果不修改tomcat端口,在啟動(dòng)CAS Server之后,其他的兩個(gè)tomcat 客戶端就無(wú)法啟動(dòng)了,因?yàn)槎丝诒徽加昧?,所以這里需要修改兩個(gè)tommcat 客戶端的端口 。
修改client1端口:
編輯D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client1\conf\server.xml文件,找到如下內(nèi)容:

image.png

將其中的8080端口和8009端口修改成其它 4位數(shù)字的端口號(hào)
我這里將其修改為:18080 和 18009。即,如下:


image.png

修改client2端口:
編輯D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client2\conf\server.xml文件,找到如下內(nèi)容:

image.png

將其中的8080端口和8009端口修改成:28080 和 28009


image.png

然后啟動(dòng)發(fā)現(xiàn)啟動(dòng)不了,網(wǎng)上查了一下資料,發(fā)現(xiàn)還有一個(gè)地方需要修改:

image.png

將兩個(gè)tomcat客戶端的該端口分別改成: 8006 和 8007。

配置host

網(wǎng)上說(shuō):因?yàn)镃AS單點(diǎn)登錄系統(tǒng)是基于JAVA安全證書的 https 訪問(wèn), 要使用CAS單點(diǎn)登錄必須要配置域名, cas是不能通過(guò)ip訪問(wèn)的。首先cas只能通過(guò)域名來(lái)訪問(wèn),不能通過(guò)ip訪問(wèn),同時(shí)cas Server是生成證書yiduan,所以要求比較嚴(yán)格,所以如果不這么做的話,及時(shí)最終按照教程配置完成,cas也可以正常訪問(wèn),訪問(wèn)一個(gè)客戶端應(yīng)用雖然能進(jìn)入cas驗(yàn)證首頁(yè),但是,當(dāng)輸入信息正確后,cas在回調(diào)轉(zhuǎn)入你想訪問(wèn)的客戶端應(yīng)用的時(shí)候,會(huì)出現(xiàn)No subject alternative names present錯(cuò)誤異常信息,這個(gè)錯(cuò)誤也就是在上面輸入的第一個(gè)問(wèn)題答案不是域名導(dǎo)致、或者與hosts文件配置的不一致導(dǎo)致。
不是理解的很好,所以這里還是配置一下host吧。下面3個(gè)ip都是127.0.0.1,因?yàn)榄h(huán)境都是在同一臺(tái)機(jī)器,所以ip都是一致的,我們?cè)侔巡煌姆?wù)端和客戶端應(yīng)用,使用不同域名加以區(qū)分。一個(gè)域名對(duì)應(yīng)一個(gè)應(yīng)用,模擬多端

image.png

sso.castest..com =>> 對(duì)應(yīng)部署cas server的tomcat,這個(gè)虛擬域名還用于服務(wù)端證書生成
client1.castest..com =>> 對(duì)應(yīng)部署client1客戶端應(yīng)用的tomcat
client2.castest..com =>> 對(duì)應(yīng)部署client2客戶端應(yīng)用的tomcat

啟動(dòng)tomcat測(cè)試

這里的測(cè)試僅僅是測(cè)試兩個(gè)tomcat客戶端是否能夠成功啟動(dòng),并不涉及到和CAS Server相關(guān)的內(nèi)容。

分別進(jìn)入:D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client1\bin 和
D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client2\bin ,并執(zhí)行 startup.bat

在瀏覽器分地址欄分別輸入:
http://client1.castest.com:18080/examples/servlets/

http://client2.castest.com:28080/examples/servlets/

可以看到如下界面,說(shuō)明tomcat客戶端啟動(dòng)成功:

image.png

客戶端和CAS Server連接

配置 client1:
編輯 D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client1\webapps\examples\WEB-INF\web.xml 配置文件,添加如下內(nèi)容

<!-- ======================== 單點(diǎn)登錄開始 ======================== -->
    <!-- 用于單點(diǎn)退出,該過(guò)濾器用于實(shí)現(xiàn)單點(diǎn)登出功能,可選配置-->
    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!-- 該過(guò)濾器用于實(shí)現(xiàn)單點(diǎn)登出功能,可選配置。 -->
    <filter>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 該過(guò)濾器負(fù)責(zé)用戶的認(rèn)證工作,必須啟用它 -->
    <filter>
        <filter-name>CASFilter</filter-name>
        <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
        <init-param>
            <param-name>casServerLoginUrl</param-name>
            <param-value>https://sso.castest.com:8443/cas/login</param-value>
            <!--這里的server是服務(wù)端的IP-->
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://client1.castest.com:18080</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CASFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 該過(guò)濾器負(fù)責(zé)對(duì)Ticket的校驗(yàn)工作,必須啟用它 -->
    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
             <param-value>https://sso.castest.com:8443/cas/</param-value><!-- 此處必須為登錄url /cas/,帶有任何其它路徑都會(huì)報(bào)錯(cuò),如“https://sso.castest.com:8443/cas/login”,這樣也會(huì)報(bào)錯(cuò)。 -->
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://client1.castest.com:18080</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CAS Validation Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--
        該過(guò)濾器負(fù)責(zé)實(shí)現(xiàn)HttpServletRequest請(qǐng)求的包裹,
        比如允許開發(fā)者通過(guò)HttpServletRequest的getRemoteUser()方法獲得SSO登錄用戶的登錄名,可選配置。
    -->
    <filter>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--
         該過(guò)濾器使得開發(fā)者可以通過(guò)org.jasig.cas.client.util.AssertionHolder來(lái)獲取用戶的登錄名。
        比如AssertionHolder.getAssertion().getPrincipal().getName()。
    -->
    <filter>
        <filter-name>CAS Assertion Thread Local Filter</filter-name>
        <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CAS Assertion Thread Local Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- ======================== 單點(diǎn)登錄結(jié)束 ======================== -->

配置 client2:
編輯 D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64-client2\webapps\examples\WEB-INF\web.xml 配置文件,添加如下內(nèi)容

<!-- ======================== 單點(diǎn)登錄開始 ======================== -->
    <!-- 用于單點(diǎn)退出,該過(guò)濾器用于實(shí)現(xiàn)單點(diǎn)登出功能,可選配置-->
    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!-- 該過(guò)濾器用于實(shí)現(xiàn)單點(diǎn)登出功能,可選配置。 -->
    <filter>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 該過(guò)濾器負(fù)責(zé)用戶的認(rèn)證工作,必須啟用它 -->
    <filter>
        <filter-name>CASFilter</filter-name>
        <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
        <init-param>
            <param-name>casServerLoginUrl</param-name>
            <param-value>https://sso.castest.com:8443/cas/login</param-value>
            <!--這里的server是服務(wù)端的IP-->
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://client2.castest.com:28080</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CASFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 該過(guò)濾器負(fù)責(zé)對(duì)Ticket的校驗(yàn)工作,必須啟用它 -->
    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
             <param-value>https://sso.castest.com:8443/cas/</param-value><!-- 此處必須為登錄url /cas/,帶有任何其它路徑都會(huì)報(bào)錯(cuò),如“https://sso.castest.com:8443/cas/login”,這樣也會(huì)報(bào)錯(cuò)。 -->
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <param-value>http://client2.castest.com:28080</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CAS Validation Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--
        該過(guò)濾器負(fù)責(zé)實(shí)現(xiàn)HttpServletRequest請(qǐng)求的包裹,
        比如允許開發(fā)者通過(guò)HttpServletRequest的getRemoteUser()方法獲得SSO登錄用戶的登錄名,可選配置。
    -->
    <filter>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!--
         該過(guò)濾器使得開發(fā)者可以通過(guò)org.jasig.cas.client.util.AssertionHolder來(lái)獲取用戶的登錄名。
        比如AssertionHolder.getAssertion().getPrincipal().getName()。
    -->
    <filter>
        <filter-name>CAS Assertion Thread Local Filter</filter-name>
        <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>CAS Assertion Thread Local Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
    <!-- ======================== 單點(diǎn)登錄結(jié)束 ======================== -->

測(cè)試SSO功能

至此,所以配置都已經(jīng)配置完成。這時(shí)候需要測(cè)試單點(diǎn)登錄功能:

首先,重啟 tomcat client 和 tomcat client2。也就是說(shuō),在這個(gè)時(shí)候,我們的三個(gè)tomcat都已經(jīng)啟動(dòng)成功,分別為:CAS Server 、 client1 、client2。

然后,訪問(wèn):http://client1.castest.com:18080/examples/servlets/servlet/HelloWorldExample

這時(shí)候,會(huì)發(fā)現(xiàn)瀏覽器地址重定向到了:

https://sso.castest.com:8443/cas/login?service=http%3A%2F%2Fclient1.castest.com%3A18080%2Fexamples%2Fservlets%2Fservlet%2FHelloWorldExample

image.png

不過(guò)后面那一串是什么東西?利用在線工具對(duì)這個(gè)地址解碼,得到以下地址:
https://sso.castest.com:8443/cas/login?service=http://client1.castest.com:18080/examples/servlets/servlet/HelloWorldExample

是不是很熟悉,現(xiàn)在這個(gè)過(guò)程,是不是很像 “CAS SSO 原理”里面的內(nèi)容呢?也就是說(shuō),在我們?cè)L問(wèn)client1的時(shí)候,按CAS 認(rèn)證流程走了一遍。后面那個(gè)參數(shù):service=xxx,就是我們認(rèn)證成功之后重定向的地址,也就是我們當(dāng)前訪問(wèn)的地址。

這時(shí)候輸入用戶名Moxie 密碼 Admin,發(fā)現(xiàn)界面出現(xiàn)了 我想想要訪問(wèn)的資源,同時(shí),觀察瀏覽器地址欄的變化:

image.png

多了一個(gè) ;jsessionid=EFDD121B137669268985F413E745891C

這時(shí)候我們?cè)僭L問(wèn) client2,因我我們剛剛已經(jīng)登錄過(guò)一次了,所以,這次在我們?cè)L問(wèn)client2的時(shí)候,按理來(lái)說(shuō)是不需要重新登錄的,下面進(jìn)行測(cè)試:

在瀏覽器地址欄輸入:

http://client2.castest.com:28080/examples/servlets/servlet/HelloWorldExample

然而,效果卻并不是我們預(yù)期的那樣,竟然出現(xiàn)以下界面:

image.png

當(dāng)我們點(diǎn)擊here的時(shí)候,出現(xiàn)以下錯(cuò)誤:

image.png

這是什么原因?經(jīng)過(guò)一番google,發(fā)現(xiàn)原來(lái)是:CAS服務(wù)器的ST票據(jù)有效期時(shí)間太短,默認(rèn)是10秒。開發(fā)在debug時(shí),非常容易超過(guò)10秒,所以會(huì)發(fā)生TicketValidationException異常。
首先,設(shè)置CAS Server的超時(shí)時(shí)間:
編輯D:\GreenSoft\Apach\Tomcat\Tomcat-8.0.30-x64\webapps\cas\WEB-INF\cas.properties
設(shè)置有效時(shí)間為: 3600

image.png

重啟CAS Server, 并且登出。
然后訪問(wèn)
http://client1.castest.com:18080/examples/servlets/servlet/HelloWorldExample
提示輸入用戶名密碼,我們輸入 Moxie Admin 進(jìn)行登錄,出現(xiàn)以下界面;

image.png

說(shuō)明client1沒(méi)有問(wèn)題。

然后訪問(wèn)client2
http://client2.castest.com:28080/examples/servlets/servlet/HelloWorldExample
同樣出現(xiàn)以下界面

image.png

至此,單點(diǎn)配置成功。

繼承SpringSecurity

spring-security集成,主要介紹spring-security-cas的使用。

配置文件

根據(jù)上面的幾篇文章,可以知道CAS分為Client端和Server端,這里主要講的是Client端。

casSecurity.xml

<!-- 此文件用于CAS sso登錄方式 -->
<beans:beans xmlns="http://www.springframework.org/schema/security"
             xmlns:beans="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
                                 http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd">
    <!-- CAS 基本屬性配置-->
    <beans:bean id="serviceProperties"
                class="org.springframework.security.cas.ServiceProperties">
        <beans:property name="service"
                        value="${cas.service}"/>
        <beans:property name="sendRenew" value="false"/>
    </beans:bean>

    <!-- CAS 認(rèn)證配置 -->
    <http entry-point-ref="casEntryPoint" access-decision-manager-ref="accessDecisionManager">
        <csrf request-matcher-ref="csrfCasSecurityRequestMatcher"/>
        <intercept-url pattern="/resources/**" access="permitAll"/>
        <intercept-url pattern="/lib/**" access="permitAll"/>
  <!--      <intercept-url pattern="/common/**" access="permitAll"/>-->
        <!-- <intercept-url pattern="/login" access="permitAll" />
         <intercept-url pattern="/login.html" access="permitAll" />
         <intercept-url pattern="/verifiCode" access="permitAll" />-->
        <intercept-url pattern="/timeout" access="permitAll"/>
        <intercept-url pattern="/websocket/**" access="permitAll"/>
        <intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
        <!--   <access-denied-handler error-page="/access-denied"/>
           <session-management invalid-session-url="/timeout"/>-->

        <!--<form-login login-page='/login' authentication-success-handler-ref="successHandler"
                    authentication-failure-handler-ref="loginFailureHandler"/>-->
        <!--authentication-failure-url="/login?error=true"/>-->
        <!-- 驗(yàn)證碼攔截器 -->
        <!--  <custom-filter ref="captchaVerifierFilter" before="FORM_LOGIN_FILTER"/>-->


        <custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
        <custom-filter position="CAS_FILTER" ref="casFilter"/>
        <custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>

        <headers defaults-disabled="true">
            <cache-control/>
        </headers>
    </http>

    <!-- 認(rèn)證管理器,確定用戶,角色及相應(yīng)的權(quán)限 -->
    <beans:bean id="accessDecisionManager" class="org.springframework.security.access.vote.UnanimousBased">
        <!-- 投票器 -->
        <beans:constructor-arg>
            <beans:list>
                <beans:bean class="com.hand.hap.security.PermissionVoter"/>
                <beans:bean class="org.springframework.security.web.access.expression.WebExpressionVoter"/>
                <beans:bean class="org.springframework.security.access.vote.RoleVoter"/>
                <beans:bean class="org.springframework.security.access.vote.AuthenticatedVoter"/>

            </beans:list>
        </beans:constructor-arg>
    </beans:bean>


    <!-- CAS Filter 配置 -->
    <beans:bean id="casFilter"
                class="org.springframework.security.cas.web.CasAuthenticationFilter">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationSuccessHandler" ref="successHandler"/>
    </beans:bean>

    <beans:bean id="successHandler" class="com.hand.hap.security.CustomAuthenticationSuccessHandler">
        <beans:property name="defaultTargetUrl" value="/index"/>
    </beans:bean>


    <beans:bean id="casEntryPoint"
                class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
        <beans:property name="loginUrl" value="${cas.ssoserver.loginurl}"/>
        <beans:property name="serviceProperties" ref="serviceProperties"/>
    </beans:bean>


    <authentication-manager alias="authenticationManager">
        <authentication-provider ref="casAuthenticationProvider"/>
        <!-- <authentication-provider user-service-ref="customUserDetailsService">
             <password-encoder ref="passwordManager"/>
         </authentication-provider>-->
    </authentication-manager>

    <beans:bean id="casAuthenticationProvider"
                class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
        <beans:property name="serviceProperties" ref="serviceProperties"/>
        <beans:property name="authenticationUserDetailsService" ref="customAuthenticationUserDetailsService"/>
        <beans:property name="ticketValidator">
            <beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
                <beans:constructor-arg index="0" value="${cas.ssoserver.url}"/>
            </beans:bean>
        </beans:property>
        <beans:property name="key" value="an_id_for_this_auth_provider_only"/>
    </beans:bean>


    <beans:bean id="customAuthenticationUserDetailsService"
                class="com.hand.hap.security.CustomAuthenticationUserDetailsService">
    </beans:bean>


    <beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
    <!-- This filter redirects to the CAS Server to signal Single Logout should be performed -->
    <beans:bean id="requestSingleLogoutFilter"
                class="org.springframework.security.web.authentication.logout.LogoutFilter">
        <beans:constructor-arg value="${cas.ssoserver.logouturl}"/>
        <beans:constructor-arg>
            <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
        </beans:constructor-arg>
        <beans:property name="filterProcessesUrl" value="/logout"/>
    </beans:bean>

    <beans:bean id="csrfCasSecurityRequestMatcher" class="com.hand.hap.security.CsrfSecurityRequestMatcher">
        <beans:property name="excludeUrls">
            <beans:list>
                <beans:value>/login</beans:value>
                <beans:value>/websocket/**</beans:value>
                <beans:value>/ureport/**</beans:value>
            </beans:list>
        </beans:property>
    </beans:bean>

    <!-- <beans:bean id="captchaVerifierFilter" class="com.hand.hap.security.CaptchaVerifierFilter">
         <beans:property name="captchaField" value="verifiCode"/>
     </beans:bean>
     <beans:bean id="loginFailureHandler" class="com.hand.hap.security.LoginFailureHandler"/>-->
</beans:beans>

config.properties

cas.service=http://localhost:8080/hap/login/cas
cas.ssoserver.loginurl=https://localhost:8088/sso/login
cas.ssoserver.url=https://localhost:8088/sso
cas.ssoserver.logouturl=https://localhost:8088/sso/logout?service=http://localhost:8080/hap

在Spring Security中,通過(guò)設(shè)置entry-point-ref="第三方登錄入口",可以在訪問(wèn)系統(tǒng)首頁(yè)的時(shí)候進(jìn)行登錄跳轉(zhuǎn)。它在系統(tǒng)進(jìn)行登錄認(rèn)證的過(guò)程會(huì)進(jìn)行認(rèn)證,認(rèn)證不通過(guò)則拋出一個(gè)異常給ExceptionTranslationFilter,由它進(jìn)行通過(guò)entry-point-ref設(shè)置的入口點(diǎn)進(jìn)行處理。

 <custom-filter position="CAS_FILTER" ref="casFilter"/>

position="CAS_FILTER"就表示將定義的 Filter 放在 CAS_FILTER 對(duì)應(yīng)的那個(gè)位置,這里對(duì)應(yīng)的是 casFilter

    <!-- CAS Filter 配置 -->
    <beans:bean id="casFilter"
                class="org.springframework.security.cas.web.CasAuthenticationFilter">
        <beans:property name="authenticationManager" ref="authenticationManager"/>
        <beans:property name="authenticationSuccessHandler" ref="successHandler"/>
    </beans:bean>


    <!-- 登錄成功處理 -->
    <beans:bean id="successHandler" class="com.hand.hap.security.CustomAuthenticationSuccessHandler">
        <beans:property name="defaultTargetUrl" value="/index"/>
    </beans:bean>

其實(shí)在登錄時(shí)的權(quán)限校驗(yàn)和之前的一樣,區(qū)別在于

  • AuthenticationProvider 用的是 CasAuthenticationProvider
  • 使用 entry-point-ref="casEntryPoint" 來(lái)處理登錄失敗時(shí)的一些邏輯

CasAuthenticationEntryPoint 中的 commence 方法如下,重定向到 redirectUrl,這些就是我們?cè)谑褂?spring-security-cas 需要的配置信息:

    public final void commence(final HttpServletRequest servletRequest,
            final HttpServletResponse response,
            final AuthenticationException authenticationException) throws IOException,
            ServletException {

        final String urlEncodedService = createServiceUrl(servletRequest, response);
        final String redirectUrl = createRedirectUrl(urlEncodedService);

        preCommence(servletRequest, response);

        response.sendRedirect(redirectUrl);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容