小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

SSO(單點(diǎn)登錄)實(shí)施中遇到的幾個(gè)問(wèn)題

 richsky 2012-04-16

SSO(單點(diǎn)登錄)實(shí)施中遇到的幾個(gè)問(wèn)題

分類(lèi): SSO單點(diǎn)登錄 160人閱讀 評(píng)論(0) 收藏 舉報(bào)
       單點(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)起作用了。


2.jsessionid問(wèn)題

      jsessionid是java客戶端與應(yīng)用服務(wù)器維持session的一個(gè)標(biāo)識(shí),其他語(yǔ)言客戶端(如php)有其他標(biāo)識(shí)關(guān)鍵字,具體是什么還不太了解。jsessionid一般存在于瀏覽器cookie中的(這個(gè)一般java客戶端連接到應(yīng)用服務(wù)器會(huì)自動(dòng)執(zhí)行的),一般情況下不會(huì)出現(xiàn)在url中,服務(wù)器會(huì)從客戶端的cookie中取出來(lái),但是如果瀏覽器禁用了cookie的話,就要重寫(xiě)url了,顯式的將jsessionid重寫(xiě)到Url中,方便服務(wù)器來(lái)通過(guò)這個(gè)找到session的id。CAS開(kāi)源單點(diǎn)登錄SSO組件就提供了這個(gè)機(jī)制。我研究了CAS源碼,基本明白了jsessionid的處理機(jī)制。大致原理如下:用戶訪問(wèn)業(yè)務(wù)系統(tǒng),SSO客戶端攔截,重定向到SSO服務(wù)器認(rèn)證時(shí),就將請(qǐng)求路徑uri中寫(xiě)入";jsessionid=具體的session值",SSO服務(wù)器可以分辨出這個(gè)標(biāo)識(shí)值與其他客戶端請(qǐng)求不同,進(jìn)行認(rèn)證處理,返回的響應(yīng)給客戶端cookie同時(shí)也設(shè)置了jsessionid的值,之所以在uri和cookie中都設(shè)置了jsessionid,是為了雙重保障能設(shè)置jsessionid值。最后單點(diǎn)登錄成功后,返回業(yè)務(wù)系統(tǒng)訪問(wèn)地址也帶有jsessionid參數(shù),這個(gè)在uri地址中看起來(lái)很別扭。

      提供2種解決方法,如下:

     1) 可以在登錄頁(yè)面地址的請(qǐng)求地址參數(shù)中加入?yún)?shù)”&method=POST“(記住這里要求POST大寫(xiě)),這樣就可以在最后返回的訪問(wèn)uri中不顯示jsessionid。

     2)修改代碼如下:

類(lèi)org.jasig.cas.util.UrlUtils中增加方法cleanupUrl

   

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就不存在了。

3.單點(diǎn)退出時(shí)有時(shí)子系統(tǒng)未能正常退出

      我們知道正常情況下,以用戶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) {
        if (this.loggedOutAlready) {
            return true;
        }
     
        LOG.debug("Sending logout request for: " + getId());

        final String logoutRequest = "<samlp:LogoutRequest xmlns:samlp=\"urn:oasis:names:tc:SAML:2.0:protocol\" ID=\""
            + GENERATOR.getNewTicketId("LR")
            + "\" Version=\"2.0\" IssueInstant=\"" + SamlUtils.getCurrentDateAndTime()
            + "\"><saml:NameID xmlns:saml=\"urn:oasis:names:tc:SAML:2.0:assertion\">@NOT_USED@</saml:NameID><samlp:SessionIndex>"
            + sessionIdentifier + "</samlp:SessionIndex></samlp:LogoutRequest>";

        HttpURLConnection connection = null;

        try {
            final URL logoutUrl = new URL(getOriginalUrl());
            final String output = "logoutRequest=" + URLEncoder.encode(logoutRequest, "UTF-8");

            connection = (HttpURLConnection) logoutUrl.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Length", ""
                + Integer.toString(output.getBytes().length));
            connection.setRequestProperty("Content-Type",
                "application/x-www-form-urlencoded");
            final DataOutputStream printout = new DataOutputStream(connection
                .getOutputStream());
            printout.writeBytes(output);
            printout.flush();
            printout.close();

            final BufferedReader in = new BufferedReader(new InputStreamReader(connection
                .getInputStream()));

            while (in.readLine() != null) {
                // nothing to do
            }

            return true;
        } catch (final Exception e) {
            return false;
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
            this.loggedOutAlready = 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) {
         LOG.error("--------------Sending logout request for URL: " + getOriginalUrl()+"Network connection failed.");
           throw new Exception(e);
        } finally {

。。。

說(shuō)明:

4.有些請(qǐng)求路徑不需要單點(diǎn)登錄過(guò)濾器攔截

       業(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 {
        BREAK, GOON, RETURN
    }                    
                                                                                                                                                          

...

public void doFilter(
        ServletRequest request,
        ServletResponse response,
        FilterChain fc){

。。。

CASReceipt receipt = (CASReceipt) session.getAttribute(CAS_FILTER_RECEIPT);

if (receipt != null && isReceiptAcceptable(receipt)) {
           log.trace("CAS_FILTER_RECEIPT attribute was present and acceptable - passing  request through filter..");
             fc.doFilter(request, response);
             return;
         }else{
             responeType = beforeDoSSOFilter(request, response);
             if(ResponseType.RETURN==responeType){
              return ;
             }else if(ResponseType.BREAK==responeType) {
                 fc.doFilter(request, response);
                 return;
             }  //else go on
         }

}  

//過(guò)濾器的前置處理

public ResponseType beforeDoSSOFilter(ServletRequest request,
   ServletResponse response) {
  return ResponseType.GOON;

 }

}

 

注:主要看原CASFilter 類(lèi)紅字部分?jǐn)U展代碼。

擴(kuò)展實(shí)現(xiàn)類(lèi)BMCASFilter

package com.sitechasia.sso.bmext;

public class BMCASFilter extends CASFilter {                                                                                                                                                                                                                                                
 private final Log log = LogFactory.getLog(this.getClass());
    private static String ssoclient_passedPathSet;//設(shè)置不被sso過(guò)濾器攔截的請(qǐng)求路徑,需要符合url路徑通配符,多個(gè)路徑可以","分割
 public static final String PASSEDPATHSET_INIT_PARAM="passedPathSet";//web.xml配置文件中的參數(shù)
 @Override
 public void init(FilterConfig config) throws ServletException {
  super.init(config);
  ssoclient_passedPathSet = SSOClientPropertiesSingleton.getInstance().getProperty(ClientConstants.SSOCLIENT_PASSEDPATHSET)==null?config.getInitParameter(PASSEDPATHSET_INIT_PARAM):SSOClientPropertiesSingleton.getInstance().getProperty(ClientConstants.SSOCLIENT_PASSEDPATHSET);
 }
   
    @Override
 public ResponseType beforeDoSSOFilter(ServletRequest request,
   ServletResponse response) {
    if (ssoclient_passedPathSet != null) {//路徑過(guò)濾
     HttpServletRequest httpRequest =(HttpServletRequest)request;
           String requestPath = httpRequest.getRequestURI();
//           String ls_requestPath = UrlUtils.buildFullRequestUrl(httpRequest.getScheme(), httpRequest.getServerName(), httpRequest.getServerPort(), requestPath, null);
          
        PathMatcher  matcher = new AntPathMatcher();
        String passedPaths[]=null;
        passedPaths =ssoclient_passedPathSet.split(",");
        
        if(passedPaths!=null){
         boolean flag;
         for (String passedPath : passedPaths) {
          flag = matcher.match(passedPath, requestPath);//ls_requestPath
                if(flag){
                      log.info("sso client request path '"+requestPath+"'is matched,filter chain will be continued.");
                  return ResponseType.BREAK;
                }
      }
        }
    }
  return ResponseType.GOON;
 }

 
}

web.xml文件中配置修改如下:

<filter>
  <description>單點(diǎn)登陸請(qǐng)求過(guò)濾器</description>
  <filter-name>CASFilter</filter-name>
  <filter-class>com.sitechasia.sso.dmext.filter.DMCASFilter</filter-class>

...

<init-param>
   <description>排除路徑</description>
   <param-name>passedPathSet</param-name>
   <param-value>
    /**/restful/userLogin/findPassword,
    /**/restful/userLogin/findIllegalLoginCount,
    /**/restful/tenantManager/**,
    /**/restful/lock/**,
    /**/restful/export/**
   </param-value>
  </init-param>

 </filter>

<filter-mapping>
        <filter-name>CASFilter</filter-name>
        <url-pattern>/index.jsp</url-pattern>
</filter-mapping>

。。。

注:紅字部分為相應(yīng)配置內(nèi)容擴(kuò)展部分

      經(jīng)過(guò)上述這樣擴(kuò)展,配置的排除路徑作為請(qǐng)求時(shí),單點(diǎn)登錄過(guò)濾攔截就會(huì)忽略處理,實(shí)現(xiàn)了目標(biāo)功能要求。

 5.不同應(yīng)用服務(wù)實(shí)現(xiàn)要求SSO客戶端做適應(yīng)性改造

          不同應(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)看看解決方案。

5.1.Ajax客戶端

         公司有一個(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)如下:

  • 我們約定應(yīng)用系統(tǒng)的一個(gè)Ajax請(qǐng)求的標(biāo)記(如ajaxRequestFlag=ajaxRequest),在安全資源ajax調(diào)用請(qǐng)求時(shí)攜帶此請(qǐng)求參數(shù),還約定一個(gè)超時(shí)請(qǐng)求的響應(yīng)狀態(tài)值(如555),SSO客戶端的過(guò)濾器casfilter的相應(yīng)類(lèi)程序?qū)Υ思s定進(jìn)行了相應(yīng)的改造。
  • 應(yīng)用系統(tǒng)的安全資源頁(yè)面中引入文件(HttpStatusSSO.js)SSO對(duì)Axax請(qǐng)求的http狀態(tài)的處理,其中有超時(shí)時(shí)的狀態(tài)處理、判斷是否登錄、驗(yàn)證票據(jù)等的處理,都是通過(guò)ajax請(qǐng)求方式來(lái)處理的,其中依賴(lài)一個(gè)驗(yàn)證票據(jù)的資源ticketValidate.jsp。

經(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)吧。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多