shiro-ajax请求 session失效问题解决

日期:2016-6-23 10:56:56
作者:ack
访问:9754

一、背景

    最近在使用boostrap前台框架时,遇到了session超时问题。由于js是用jquery的load加载的页面,所以session超时的时候,登陆页面回嵌入到请求的html中。
    

二、思路

       1、分析原因

        由于session失效问题,导致shiro会路径指向登陆页面,因为用了jquery的load()所以页面就被嵌入到了父图层中

       2、解决

        事后处理(js),事前处理(拦截器)

       三、解决

       1、前端 + 后端

         后端:监控sesson是否失效,失效了,再判断是否是ajax请求,如果是则设置一个timeout的状态。告诉前端。

         public class SessionFilter implements Filter {  
         @Override  
         public void init(FilterConfig filterConfig) throws ServletException {  
          }  
         @Override  
        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,  
            ServletException {  
                HttpServletRequest httpServletRequest = (HttpServletRequest) request;  
                HttpServletResponse httpServletResponse = (HttpServletResponse) response;  
                //      if (httpServletRequest.getSession().getAttribute("user") == null) {  
                if (!SecurityUtils.getSubject().isAuthenticated()) {  
                     //判断session里是否有用户信息  
                     if (httpServletRequest.getHeader("x-requested-with") != null  
                             && httpServletRequest.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {  
                     //如果是ajax请求响应头会有,x-requested-with  
                     httpServletResponse.setHeader("sessionstatus", "timeout");//在响应头设置session状态  
                     return;  
                  }  
                }  
              chain.doFilter(request, response);  
         }  
         @Override  
         public void destroy() {  
         }  
      }  
         前端:由于用到了load() (其实也是ajax请求),所以可以用ajax全局设置解决,
     
         $.ajaxSetup({
              complete:function(XMLHttpRequest,textStatus){  
              //通过XMLHttpRequest取得响应头,sessionstatus,  
              var sessionstatus=XMLHttpRequest.getResponseHeader("sessionstatus");   
             if(sessionstatus=="timeout"){  
                   //如果超时就处理 ,指定要跳转的页面  
                   window.location = "/loginUI";  
              }  
          } 
        });
        这种解决方法源地址 :http://zhuchengzzcc.iteye.com/blog/1830567
        还有一种是纯前端也是 $.ajaxSetup这个,但是忘记地址了,也没验证。好像是oschina的一篇文章。

     2、纯后端

        也是受到上面的启发,在后端的时候既然知道了session有问题,就可以直接在后端写js了。省去前端问题。
      
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.ack.bmt.auth.util.ShiroUtil;
public class SessionFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String uri = httpServletRequest.getRequestURI();
        boolean b = uri.indexOf("ajaxLogin") >= 0; //ajax 登陆 排除
        if (!ShiroUtil.hasAuthenticated() && !b) {
            // 判断session里是否有用户信息
            if (httpServletRequest.getHeader("x-requested-with") != null
                    && httpServletRequest.getHeader("x-requested-with")
                            .equalsIgnoreCase("XMLHttpRequest")) {
                // 如果是ajax请求响应头会有,x-requested-with
                //httpServletResponse.setHeader("sessionstatus", "timeout");// 在响应头设置session状态
                redirect(httpServletRequest, httpServletResponse);
                return;
            }
        }
        chain.doFilter(request, response);
    }
    @Override
    public void destroy() {
    }
    void redirect(HttpServletRequest request, HttpServletResponse response) {
        response.setHeader("sessionstatus", "timeout");// 在响应头设置session状态
        response.setContentType("text/html");
        PrintWriter out;
        try {
            out = response.getWriter();
            out.print("<script>window.location = \"/loginUI\";</script>");
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}


四、总结


  上面的第一种方法,用户体验很不好,就是,登陆页面还是会嵌入在其他页面中,然后在跳转到登陆。
  第二种就没哟这么明显了。