單點登錄,session超時, ajax鏈接處理

 

1 錯誤場景                                   

     cas session 超時問題:XMLHttpRequest cannot loadhttps://www.hf.com:8443/cas/login?service=http%3A%2F%2Flocalhost%3A8080%2Fvms%2Fcheck%2FfindPendingCheck%2F. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8080’ is therefore not allowed access.

    部署問題:用nginx封裝,service攜帶不過來。

 2 cas 針對session超時設置                       

    cas對於session超時設置,可以設置文件cas\WEB-INF\spring-configuration\ticketExpirationPolicies.xml 進行設置,如下所示:

  1. <bean id=“grantingTicketExpirationPolicy” class=“org.jasig.cas.ticket.support.RememberMeDelegatingExpirationPolicy”>  
  2.        <property name=“sessionExpirationPolicy”>  
  3.            <bean class=“org.jasig.cas.ticket.support.TimeoutExpirationPolicy”>  
  4.             <constructor-arg index=“0” value=“20000” />  
  5.                     </bean>  
  6.        </property>  
<bean id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.RememberMeDelegatingExpirationPolicy">
       <property name="sessionExpirationPolicy">
           <bean class="org.jasig.cas.ticket.support.TimeoutExpirationPolicy">
            <constructor-arg index="0" value="20000" />
                    </bean>
       </property>
  1. <bean id=“serviceTicketExpirationPolicy” class=“org.jasig.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy”>  
  2.     <!– This argument is the number of times that a ticket can be used before its considered expired. –>  
  3.     <constructor-arg  
  4.         index=“0”  
  5.         value=“1” />  
  6.       
  7.     <!– This argument is the time a ticket can exist before its considered expired.  –>  
  8.     <constructor-arg  
  9.         index=“1”  
  10.         value=“20000” />  
  11. </bean>  
    <bean id="serviceTicketExpirationPolicy" class="org.jasig.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy">
        <!-- This argument is the number of times that a ticket can be used before its considered expired. -->
        <constructor-arg
            index="0"
            value="1" />

        <!-- This argument is the time a ticket can exist before its considered expired.  -->
        <constructor-arg
            index="1"
            value="20000" />
    </bean>


    上述兩個bean中,設置爲20000毫秒(設置超時單位爲毫秒),上述另個bean的機制就如同session機制一樣,當用戶沒有與服務器的交互超過20秒,點擊url,便會自動轉到登錄界面。單只是設置這一點是不夠的,會有問題的。

    問題:當你的項目中也有對session的設置,以及對session時間的設置的時候,只設置cas的session超時是不管事的。

 3 配置完畢,對於ajax請求出現的錯誤        

    問題的解決:所以我們需要把項目中session超時的時間和cas session超時的時間設置爲一致,因爲cas對session超時的處理,是在cas-client-core-3.2.1.jar 包中,而cas的客戶端是和項目放在一起的,所以對session處理機制是一樣的。

 

    當然上述的處理一般情況下是沒有問題的,但當遇到ajax請求,就不可以了,會報如下錯誤:

XMLHttpRequest cannot load https://www.hf.com:8443/cas/login?service=http%3A%2F%2Flocalhost%3A8080%2Fvms%2Fcheck%2FfindPendingCheck%2F. No ‘Access-Control-Allow-Origin’ header is present on the requested resource. Origin ‘http://localhost:8080’ is therefore not allowed access.

    千萬別被Origin矇蔽,開始定位錯誤定位在跨域問題,因爲網上查找說也是跨域問題,而實際上對於非ajax請求,cas攔截處理後是可以跳轉到登錄頁面的,這說明了是可以請求給cas的,只不過cas對ajax的請求無法做出session失效的處理,這怎麼辦呢?只能去改CAS源碼了。不知道是cas矮,還是自己太矮了。。。

 4 修改CAS源碼,解決上述問題   

    經過查看錯誤日誌,找到cas打印日誌的地方,找到cas處理session的方法,修改的是/CAS_Client/src/org/jasig/cas/client/authentication/AuthenticationFilter.Java這個java類。修改的doFilter方法如下所示。

  1. public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {  
  2.       final HttpServletRequest request = (HttpServletRequest) servletRequest;  
  3.       final HttpServletResponse response = (HttpServletResponse) servletResponse;  
  4.       final HttpSession session = request.getSession(false);  
  5.       final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;  
  6.   
  7.       if (assertion != null) {  
  8.           filterChain.doFilter(request, response);  
  9.           return;  
  10.       }  
  11.   
  12.       final String serviceUrl = constructServiceUrl(request, response);  
  13.       final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());  
  14.       final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);  
  15.   
  16.       if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {  
  17.           filterChain.doFilter(request, response);  
  18.           return;  
  19.       }  
  20.   
  21.       final String modifiedServiceUrl;  
  22.   
  23.       log.debug(”no ticket and no assertion found”);  
  24.       if (this.gateway) {  
  25.           log.debug(”setting gateway attribute in session”);  
  26.           modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);  
  27.       } else {  
  28.           modifiedServiceUrl = serviceUrl;  
  29.       }  
  30.       if (log.isDebugEnabled()) {  
  31.           log.debug(”Constructed service url: ” + modifiedServiceUrl);  
  32.       }  
  33.         
  34.       final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);  
  35.   
  36.       if (log.isDebugEnabled()) {  
  37.           log.debug(”redirecting to \”“ + urlToRedirectTo + “\”“);  
  38.       }  
  39.         
  40.       log.debug(”判斷拼接的過程,參數, 最終拼接好的地址爲: \”“ + urlToRedirectTo + “\”“);  
  41.         
  42.       //response.sendRedirect(urlToRedirectTo);  
  43.       String url = request.getRequestURL().toString();  
  44.       log.debug(”url——request.getRequestURL().toString()=———:” + url);  
  45.       String contextPath = request.getContextPath();  
  46.       log.debug(”contextPath ———request.getContextPath()=——-:” + contextPath);  
  47.         
  48.       url = url.substring(0, (url.indexOf(contextPath)+contextPath.length()));  
  49.       log.debug(”url = ——session消失,截取到項目的url—” + url);  
  50.       String urls = urlToRedirectTo;  
  51.         
  52.       //判斷是否是第一次轉到.  
  53.       if(“”.equals(url)||url==null||url.length()==0){  
  54.           
  55.         log.debug(”url–第一次爲空,不截取—–” + url);  
  56.         urls = urlToRedirectTo;  
  57.         //response.sendRedirect(urlToRedirectTo);  
  58.       }else{  
  59.         urls = urls.substring(0, (urls.indexOf(“service=”)+8)) + URLEncoder.encode(url,“UTF-8”);  
  60.       }  
  61.         
  62.       log.debug(”urls –最終輸入到瀏覽器的地址是———–” + urls);  
  63.         
  64. response.setContentType(”text/html;charset=UTF-8”);  
  65. response.getWriter().write(”<script languge=’javascript’>window.location.href=’”+urls+“/’</script>”);  
  66.   }  
  public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) servletRequest;
        final HttpServletResponse response = (HttpServletResponse) servletResponse;
        final HttpSession session = request.getSession(false);
        final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;

        if (assertion != null) {
            filterChain.doFilter(request, response);
            return;
        }

        final String serviceUrl = constructServiceUrl(request, response);
        final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
        final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);

        if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
            filterChain.doFilter(request, response);
            return;
        }

        final String modifiedServiceUrl;

        log.debug("no ticket and no assertion found");
        if (this.gateway) {
            log.debug("setting gateway attribute in session");
            modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
        } else {
            modifiedServiceUrl = serviceUrl;
        }
        if (log.isDebugEnabled()) {
            log.debug("Constructed service url: " + modifiedServiceUrl);
        }

        final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);

        if (log.isDebugEnabled()) {
            log.debug("redirecting to \"" + urlToRedirectTo + "\"");
        }

        log.debug("判斷拼接的過程,參數, 最終拼接好的地址爲: \"" + urlToRedirectTo + "\"");

        //response.sendRedirect(urlToRedirectTo);
        String url = request.getRequestURL().toString();
        log.debug("url------request.getRequestURL().toString()=---------:" + url);
        String contextPath = request.getContextPath();
        log.debug("contextPath ---------request.getContextPath()=-------:" + contextPath);

        url = url.substring(0, (url.indexOf(contextPath)+contextPath.length()));
        log.debug("url = ------session消失,截取到項目的url---" + url);
        String urls = urlToRedirectTo;

        //判斷是否是第一次轉到.
        if("".equals(url)||url==null||url.length()==0){

            log.debug("url--第一次爲空,不截取-----" + url);
            urls = urlToRedirectTo;
            //response.sendRedirect(urlToRedirectTo);
        }else{
            urls = urls.substring(0, (urls.indexOf("service=")+8)) + URLEncoder.encode(url,"UTF-8");
        }

        log.debug("urls --最終輸入到瀏覽器的地址是-----------" + urls);

        response.setContentType("text/html;charset=UTF-8");
        response.getWriter().write("<script languge='javascript'>window.location.href='"+urls+"/'</script>");
    }


 

    這樣不但解決了cas對ajax地址處理,並且解決了另一個問題,因爲最初的改動不是上述的代碼,中間出現了一個小插曲,部署的時候出現的bug,登錄時service參數攜帶不過來。當我們把項目部署到Linux上時,用nginx代理,並配置tomcat的sever.xml文件封裝項目名稱, 則樣,域名“封裝”了ip+端口號+項目名稱,用戶不需要再輸入項目名稱了。所以代碼中對用戶第一次登錄做判斷,判斷是否是第一次登錄還是session失效調用的這個方法,這樣就解決了nginx代理出現的問題了。

 5  總結                                          

    錯誤未出現時:黑暗前的黎明

    錯誤出現時:電閃雷鳴

    錯誤解決中:時間就像過火車

    錯誤解決完畢:原來神馬都是浮雲啊

 方法上:這個過程就像是你回到家發現鑰匙丟在路上了,找到開門的鑰匙,要一步一個腳印的去找,對了一步再進行下一步,到底是哪一步找到了鑰匙?到底是哪一步,找到了錯誤?要相信,你永遠被錯誤幹不掉,只是你又幹掉了錯誤。是一次又一次的錯誤在改變你,而錯誤永遠變不了,就像倉央嘉措的那首情詩,《見或不見》.

bug對我的感情上:你見,或者不見我;我就在那裏;不悲不喜;你念,或者不念我;情就在那裏;不來不去;你愛,或者不愛我;愛就在那裏;不增不減;你跟,或者不跟我;我的手就在你的手裏;不捨不棄;來我的懷裏;或者讓我住進你的心裏;默然,相愛;寂靜,歡喜;



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章