日期:2014-05-16  浏览次数:20703 次

(转)EXT结合acegi解决ajax提交时session失效的问题
背景

  B/S系统中,客户端向服务器端提交的http请求,可以分为两种:非ajax请求(一般http请求)和ajax请求。Acegi是通过一系列的filter实现的安全框架(现在好像升级成spring sceurity了)。对于非ajax请求时的session失效,acegi已经完成,即如果session失效则自动跳转到登录页面。

解决方案

  Acegi对于session失效(或其他web异常)的处理是通过“org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint”类来实现的,具体配置如下:
<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
                <property name="loginFormUrl" value="/login.jsp"/>
                <property name="forceHttps" value="false"/>
            </bean>
        </property>
 </bean>


如代码所示,acegi检测到session失效时就跳转到登录页面“/login.jsp”。实际上不管是非ajax请求还是ajax请求,acegi都是这么处理的。不过因为ajax不能实现页面跳转,所以这时的session失效处理的办法就“失效”了,客户在提交ajax后会得不到正确的处理或提示。解决这个问题的关键在于把两种http请求区分开来。本人对http的原理了解不深,笨人用笨办法,请出Ext(封装了ajax的一个js框架,其他js框架按照同样的原理理论上也可以实现)来:
Ext.Ajax.on('beforerequest', function(){
   Ext.Ajax.extraParams={'ajax_extraParams':'true'};
 }, this);//


如以上代码所示,EXT在ajax提交前和处理完成后提供了事件接口,分别是“'beforerequest'”和“'requestcomplete'”,我们就在这两个事件上想办法。对所有的ajax请求,我们都加上一个特殊的参数用以与非ajax请求区分“Ext.Ajax.extraParams={'ajax_extraParams':'true'};”。除此之外,我们还需acegi的辅助,修改它处理session失效时的几个参数配置:

<bean id="exceptionTranslationFilter" class="org.acegisecurity.ui.ExceptionTranslationFilter">
        <property name="authenticationEntryPoint">
            <bean class="org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint">
                <property name="loginFormUrl" value="/checkLogin.jsp"/>
                <property name="forceHttps" value="false"/>
                <property name="serverSideRedirect" value="true"/>
            </bean>
        </property>
 </bean>


与前面提到的acegi配置相比,修改了两个地方:"loginFormUrl"修改成"/checkLogin.jsp",即检测到失效后跳转的路径;增加了一个"serverSideRedirect"属性并将其配置成true,即采用“forward”方式跳转(false则才用“redirect”方式跳转),之所以要采用“forward”方式是因为我们需要获取前面由EXT提交过来用以检测ajax请求的参数“ajax_extraParams”。

这样跳转到“checkLogin.jsp”后,我们就可以根据是否ajax请求作出我们自己的处理了:

<%
  String extraParams=request.getParameter("ajax_extraParams");
  System.out.println("extraParams:"+extraParams);
  if("true".equals(extraParams)){
	  out.print("{ajax_session_invalid:true}");
	  return;
  }
  String contextPath = request.getContextPath();
  response.sendRedirect(contextPath+"/login.jsp");
%>

代码里面读取“ajax_extraParams”参数,如果没有此参数,则直接跳转到登录页面;如有且为“true”我们就认为是ajax请求,则把session失效的标记以json的方式写会客户端,最后由EXT来处理:
Ext.Ajax.on('requestcomplete', function(conn,response){
	try{
	  var resp=Ext.decode(response.responseText);
	  if(resp.ajax_session_invalid){
	  	alert("请重新登陆!")
	  	location=g_rootPath+"login.jsp";
	  }
	}catch(e){	}
}, this);


以上代码即EXT在ajax完成事件通过“ajax_session_invalid”属性来检测是否session失效,如果失效则提示用户,然后跳转到登录界面。



后记

   整个解决方案里面需要注意两个地方:acegi的"serverSideRedirect"属性必须是“1.0.3”及其以后的版本才有;另外一个就是我们的两个参数名(ajax_extraParams和ajax_session_invalid)必须比较特殊,以与业务属性区分。


转自:http://javaphoon.iteye.com/blog/375043