Shiro:ajax的session超時處理


本問題解決方案參照網站多篇文章融合解決,在此表示感謝!

環境:springboot+shiro+jquery-easyui

問題:在ajax請求時,如果此時session已經失效,系統沒有自動跳轉到登錄頁面。后來在服務端加了判斷ajax請求的代碼,結果還是沒有用,無法取到ajax特定的head值(X-Requested-With)。發現jquery-easyui表單提交時沒有就沒有傳遞這個值。

解決辦法:

1.添加攔截器

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SessionFilter extends FormAuthenticationFilter {

  private Logger logger = LoggerFactory.getLogger(SessionFilter.class);
  private final static String X_REQUESTED_WITH_STRING = "X-Requested-With";
  private final static String XML_HTTP_REQUEST_STRING = "XMLHttpRequest";
  private final static String SESSION_OUT_STIRNG = "sessionOut";

  @Override
  protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
    if (this.isLoginRequest(servletRequest, servletResponse)) {
      if (this.isLoginSubmission(servletRequest, servletResponse)) {
        return this.executeLogin(servletRequest, servletResponse);
      } else {
        return true;
      }
    } else {
      if (isAjax((HttpServletRequest) servletRequest)) {
        servletResponse.getWriter().print(SESSION_OUT_STIRNG);
      } else {
        this.saveRequestAndRedirectToLogin(servletRequest, servletResponse);
      }
      return false;
    }
  }

  public boolean isAjax(HttpServletRequest httpServletRequest) {
    String header = httpServletRequest.getHeader(X_REQUESTED_WITH_STRING);
    if (XML_HTTP_REQUEST_STRING.equalsIgnoreCase(header)) {
      logger.debug("當前請求為Ajax請求:{}", httpServletRequest.getRequestURI());
      return Boolean.TRUE;
    }
    logger.debug("當前請求非Ajax請求:{}", httpServletRequest.getRequestURI());
    return Boolean.FALSE;
  }

}

2.覆蓋默認shiro攔截器

@Bean
  public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    // 必須設置 SecurityManager
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    // 如果不設置默認會自動尋找Web工程根目錄下的"/login.jsp"頁面
    shiroFilterFactoryBean.setLoginUrl("/login");
    // 登錄成功后要跳轉的鏈接
    shiroFilterFactoryBean.setSuccessUrl("/index");
    // 未授權界面;
    shiroFilterFactoryBean.setUnauthorizedUrl("/403");
    // 自定義攔截器
    Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
    // 限制同一帳號同時在線的個數。
    filtersMap.put("kickout", filterKickoutSessionControl());
    shiroFilterFactoryBean.setFilters(filtersMap);
    // 權限控制map.
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
    filterChainDefinitionMap.put("/servlet/authimage", "anon");
    filterChainDefinitionMap.put("/**", "authc");
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    Map<String, Filter> filters=new LinkedHashMap<>();
    filters.put("authc", new SessionFilter());
    shiroFilterFactoryBean.setFilters(filters);
    return shiroFilterFactoryBean;
  }

這個是重點,覆蓋shiro默認的攔截器:

Map<String, Filter> filters=new LinkedHashMap<>();
    filters.put("authc", new SessionFilter());
    shiroFilterFactoryBean.setFilters(filters);

3.改造前端

一開始采用了修改form提交的參數,把iframe=false就可以提交X-Requested-With,但是這樣的異步請求實在太多,不僅僅在form提交,還有combo,tree等等。所以最后用了網上說的方法,改造$.ajax達到統一處理。

//首先備份下jquery的ajax方法  
var _ajax = $.ajax;
// 重寫jquery的ajax方法
$.ajax = function(opt) {
    // 備份opt中error和success方法
    var fn = {
        error : function(XMLHttpRequest, textStatus, errorThrown) {
        },
        success : function(data, textStatus) {
        }
    }
    if (opt.error) {
        fn.error = opt.error;
    }
    if (opt.success) {
        fn.success = opt.success;
    }

    // 擴展增強處理
    var _opt = $.extend(opt, {
        error : function(XMLHttpRequest, textStatus, errorThrown) {
            debugger;
            erro = eval("(" + XMLHttpRequest.responseText + ")");
            // 錯誤方法增強處理
            fn.error(XMLHttpRequest, textStatus, errorThrown);
        },
        success : function(data, textStatus) {
            if (data != 'sessionOut') {
                fn.success(data, textStatus)
                return false;
            } else {
                top.location.href = appPath + "/";
            }
        }
    });
    return _ajax(_opt);
};

這個地方要根據個人情況修改一下:

image


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM