|
單點(diǎn)登錄應(yīng)用中,遇到如下的幾個(gè)問(wèn)題:1.超時(shí)問(wèn)題;2.jsessionid問(wèn)題;3.單點(diǎn)退出時(shí)有時(shí)子系統(tǒng)未能正常退出;4.有些請(qǐng)求路徑不需要單點(diǎn)登錄過(guò)濾器攔截;5.不同應(yīng)用服務(wù)實(shí)現(xiàn)可能要求SSO客戶端做適應(yīng)性改造。我們具體分析一下,并提出解決方法。
1.超時(shí)問(wèn)題我們提供的CAS開(kāi)源單點(diǎn)登錄SSO組件,它部署節(jié)點(diǎn)主要有2個(gè):SSO服務(wù)器(部署內(nèi)容為一個(gè)web應(yīng)用)、應(yīng)用系統(tǒng)客戶端(部署內(nèi)容為cas客戶端casclient.jar包和相關(guān)配置文件)。因此我們根據(jù)SSO機(jī)制分析一下什么情況下會(huì)出現(xiàn)超時(shí)。多個(gè)應(yīng)用系統(tǒng)進(jìn)行SSO集成后,SSO單點(diǎn)登錄過(guò)程中,登錄成功后,應(yīng)用系統(tǒng)客戶端(以下用瀏覽器客戶端為例)的session會(huì)保存認(rèn)證后的用戶上下文,SSO服務(wù)器會(huì)生成一個(gè)用戶憑證票據(jù)(TGT)并緩存起來(lái),瀏覽器客戶端會(huì)保存TGC(瀏覽器cookie中存儲(chǔ)的TGT),TGT是作為發(fā)放SSO訪問(wèn)服務(wù)的票據(jù)(ST)的一個(gè)憑證票據(jù),發(fā)放ST票據(jù)后才能正常訪問(wèn)。而瀏覽器客戶端的session會(huì)超時(shí)(如一般web應(yīng)用客戶端可以設(shè)置session的timeout值為30分鐘或更長(zhǎng)),超時(shí)后會(huì)讓session失效,清空用戶上下文,TGC因?yàn)槿匀皇潜4嬖跒g覽器cookie中,只有關(guān)閉瀏覽器才會(huì)清除。SSO服務(wù)器端的超時(shí)主要是TGT、ST超時(shí),我們一般會(huì)設(shè)置超時(shí)值TGT為2小時(shí),ST為5分鐘。關(guān)于ST票據(jù)使用,一般在首次SSO訪問(wèn)服務(wù)時(shí)攜帶著該票據(jù)參數(shù),驗(yàn)證票據(jù)后能正常訪問(wèn)后,SSO服務(wù)器就將此ST銷(xiāo)毀失效了;關(guān)于TGT票據(jù)的使用,一般是正常訪問(wèn)時(shí)一直保持為超時(shí)時(shí)間(2小時(shí)),除非做單點(diǎn)退出會(huì)銷(xiāo)毀TGT。基于以上分析,我們可以得出結(jié)論,SSO的超時(shí)主要涉及2個(gè)要素:瀏覽器的session超時(shí)值、TGT的超時(shí)值。一般系統(tǒng)設(shè)置TGT的超時(shí)值>瀏覽器的session超時(shí)值,那么可能有2種超時(shí)情況:1.TGT超時(shí)(瀏覽器session超時(shí)值小,自然也超時(shí));2.瀏覽器session超時(shí),TGT不超時(shí)。 第一種“1.TGT超時(shí)”,這個(gè)處理很簡(jiǎn)單,用戶的有效憑證票據(jù)都失效了,自然要重新取得有效憑證票據(jù)TGT,需要做的就是重新跳轉(zhuǎn)到登錄頁(yè)面重新登錄。 第二種”2.瀏覽器session超時(shí),TGT不超時(shí)“,這時(shí)SSO服務(wù)器的TGT票據(jù),以及瀏覽器客戶端的TGC(cookie中的TGT)仍然有效。瀏覽器客戶端再次SSO訪問(wèn)時(shí)就可以攜帶TGC(與服務(wù)器的TGT對(duì)應(yīng)),向SSO服務(wù)器重新發(fā)送取得票據(jù)ST請(qǐng)求,取得票據(jù)ST后,攜帶著有效ST票據(jù)可以正常訪問(wèn)應(yīng)用系統(tǒng)了。這個(gè)過(guò)程是瀏覽器客戶端與SSO服務(wù)器的一個(gè)通訊交互,用戶可能感覺(jué)不到,不會(huì)出現(xiàn)中斷,好像能連續(xù)訪問(wèn),這是為了給用戶一個(gè)友好的訪問(wèn)體驗(yàn)。明白這個(gè)機(jī)制,就知道實(shí)際上是SSO機(jī)制在后臺(tái)起作用了。
|
|
public static final String cleanupUrl(final String url) { if (url == null) { return null; }
final int jsessionPosition = url.indexOf(";jsession");
if (jsessionPosition == -1) { return url; }
final int questionMarkPosition = url.indexOf("?");
if (questionMarkPosition < jsessionPosition) { return url.substring(0, url.indexOf(";jsession")); }
return url.substring(0, jsessionPosition) + url.substring(questionMarkPosition); } |
類(lèi)org.jasig.cas.web.flow.DynamicRedirectViewSelector的makeEntrySelection方法中修改如下行
|
default: // return new ExternalRedirect(serviceResponse.getUrl());//注釋源碼 return new ExternalRedirect(UrlUtils.cleanupUrl(serviceResponse.getUrl()));//清除url中jsessionid |
這樣運(yùn)行后,url路徑中的jsessionid就不存在了。
我們知道正常情況下,以用戶A單點(diǎn)登錄系統(tǒng),正常訪問(wèn)各子系統(tǒng),然后執(zhí)行單點(diǎn)退出時(shí),退出成功后一般跳轉(zhuǎn)回到登錄頁(yè)面要求重新登錄,這時(shí)各已登錄的子系統(tǒng)session被銷(xiāo)毀,再次以另一個(gè)用戶B登錄進(jìn)入后,各子系統(tǒng)顯示的應(yīng)當(dāng)是用戶B的數(shù)據(jù)信息??墒怯袝r(shí)卻發(fā)現(xiàn)有些子系統(tǒng)仍然顯示的是用戶A的數(shù)據(jù)信息,這屬于偶發(fā)現(xiàn)象?,F(xiàn)在分析一下產(chǎn)生這種情況可能的原因,找出解決辦法。
若想了解單點(diǎn)退出機(jī)制原理,我們可以先看看CAS源碼的SSO單點(diǎn)退出實(shí)現(xiàn)機(jī)制。參見(jiàn)我的博客中 http://blog.csdn.net/yan_dk/article/details/7095091單點(diǎn)登錄實(shí)現(xiàn)機(jī)制的【單點(diǎn)退出】部分。
我們看一下源碼,看到退出時(shí)調(diào)用類(lèi)AbstractWebApplicationService的方法logOutOfService(),代碼如下
|
public synchronized boolean logOutOfService(final String sessionIdentifier) { final String logoutRequest = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\"" HttpURLConnection connection = null; try { connection = (HttpURLConnection) logoutUrl.openConnection(); final BufferedReader in = new BufferedReader(new InputStreamReader(connection while (in.readLine() != null) { return true; |
我們看到紅字部分,在調(diào)用發(fā)生異常時(shí),代碼是直接返回false的,也就是說(shuō)單點(diǎn)退出發(fā)生錯(cuò)誤時(shí),SSO服務(wù)器并沒(méi)有做異常處理,直接返回,這樣就有可能在出現(xiàn)異常時(shí)(比如網(wǎng)絡(luò)瞬時(shí)閃斷),雖然系統(tǒng)界面退出后返回登錄頁(yè)面,但是SSO服務(wù)器并沒(méi)有退出處理,沒(méi)有銷(xiāo)毀登錄會(huì)話,所以就可能出現(xiàn)沒(méi)有真正退出,仍然顯示前一用戶的會(huì)話信息。這個(gè)應(yīng)該是CAS源碼的一個(gè)bug,解決方法是在此處積累錯(cuò)誤日志,并拋出異常處理。這樣應(yīng)該能解決此問(wèn)題。修改代碼如下:
|
。。。 } catch (final Exception e) { 。。。 |
說(shuō)明:
業(yè)務(wù)系統(tǒng)web應(yīng)用在使用單點(diǎn)登錄組件時(shí),有些請(qǐng)求路徑不需要單點(diǎn)登錄過(guò)濾器攔截,比如公共開(kāi)放的路徑,不需要認(rèn)證都可以自由訪問(wèn)的路徑,單點(diǎn)登錄過(guò)濾器配置的映射路徑一般以通配符匹配路徑,但要把這些路徑單獨(dú)提取出來(lái),讓過(guò)濾器不攔截做單點(diǎn)登錄處理,就需要對(duì)原有過(guò)濾器進(jìn)行擴(kuò)展改造,才能實(shí)現(xiàn)這個(gè)功能。
擴(kuò)展實(shí)現(xiàn)代碼如下:
|
public class CASFilter implements Filter { public static enum ResponseType { ... public void doFilter( 。。。 CASReceipt receipt = (CASReceipt) session.getAttribute(CAS_FILTER_RECEIPT); if (receipt != null && isReceiptAcceptable(receipt)) { } //過(guò)濾器的前置處理 public ResponseType beforeDoSSOFilter(ServletRequest request, } }
|
注:主要看原CASFilter 類(lèi)紅字部分?jǐn)U展代碼。
擴(kuò)展實(shí)現(xiàn)類(lèi)BMCASFilter
|
package com.sitechasia.sso.bmext; public class BMCASFilter extends CASFilter { |
web.xml文件中配置修改如下:
|
<filter> ... <init-param> <filter-mapping> 。。。 |
注:紅字部分為相應(yīng)配置內(nèi)容擴(kuò)展部分
經(jīng)過(guò)上述這樣擴(kuò)展,配置的排除路徑作為請(qǐng)求時(shí),單點(diǎn)登錄過(guò)濾攔截就會(huì)忽略處理,實(shí)現(xiàn)了目標(biāo)功能要求。
不同應(yīng)用服務(wù),對(duì)請(qǐng)求的處理方式不同,SSO客戶端常規(guī)方法不能處理的需要進(jìn)行適應(yīng)性改造。我們先看一下SSO客戶端常規(guī)方法處理請(qǐng)求,web應(yīng)用中定義一個(gè)過(guò)濾器casfilter,并配置對(duì)安全資源攔截,首次登錄系統(tǒng)、或者訪問(wèn)超時(shí)時(shí),安全資源的請(qǐng)求被過(guò)濾器casfilter攔截,將安全資源路徑包裝為service參數(shù),并重定向(http狀態(tài)為302)到SSO服務(wù)器地址進(jìn)行認(rèn)證,輸入憑證信息(用戶名、密碼等),SSO服務(wù)器經(jīng)過(guò)認(rèn)證、驗(yàn)證票據(jù)機(jī)制處理,認(rèn)證成功后,登錄通過(guò)后繼續(xù)訪問(wèn)安全資源,再次訪問(wèn)安全資源時(shí),過(guò)濾器casfilter攔截,根據(jù)用戶上下文判斷用戶已經(jīng)登錄,就不再攔截安全資源,直接正常訪問(wèn)安全資源。而有些應(yīng)用中使用其他方式處理請(qǐng)求,按上述常規(guī)方法不好處理,下面舉實(shí)例來(lái)看看解決方案。
公司有一個(gè)應(yīng)用系統(tǒng)使用Ajax客戶端來(lái)處理請(qǐng)求并取得響應(yīng),在訪問(wèn)超時(shí)時(shí),Ajax客戶端請(qǐng)求由于使用異步處理技術(shù)(只局部刷新頁(yè)面),不能將請(qǐng)求繼續(xù)302重定向到SSO服務(wù)器重新認(rèn)證處理,不能繼續(xù)訪問(wèn)安全資源,界面響應(yīng)處于一直延遲狀態(tài),很不友好。我們針對(duì)此應(yīng)用進(jìn)行適應(yīng)性改造。改造要點(diǎn)如下:
經(jīng)過(guò)上述改造后,應(yīng)用系統(tǒng)的安全資源發(fā)送攜帶ajax請(qǐng)求標(biāo)記的請(qǐng)求,在超時(shí)請(qǐng)求時(shí),SSO客戶端返回約定響應(yīng)碼(555),HttpStatusSSO.js文件判斷處理后轉(zhuǎn)發(fā)給相應(yīng)的登錄頁(yè)面重新認(rèn)證。單點(diǎn)登錄的訪問(wèn)也能夠正常的實(shí)現(xiàn)功能。這樣只擴(kuò)展了SSO客戶端組件的實(shí)現(xiàn),向下版本兼容,保證了SSO組件的統(tǒng)一完整性。
上述改造方式是通過(guò)實(shí)踐開(kāi)發(fā)出來(lái)的,可能還有更好的方法來(lái)改造擴(kuò)展,今后持續(xù)改進(jìn)吧。
|
|
來(lái)自: richsky > 《單點(diǎn)登錄》