单点登录,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对我的感情上:你见,或者不见我;我就在那里;不悲不喜;你念,或者不念我;情就在那里;不来不去;你爱,或者不爱我;爱就在那里;不增不减;你跟,或者不跟我;我的手就在你的手里;不舍不弃;来我的怀里;或者让我住进你的心里;默然,相爱;寂静,欢喜;



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