本問題解決方案參照網站多篇文章融合解決,在此表示感謝!
環境: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); };
這個地方要根據個人情況修改一下: