最近在學習shiro時遇到一個問題,在ajax請求時,若是session失效時,沒法正確的跳轉登陸頁面。在以前的項目中處理的方法是經過自定義一個過濾器來處理,session失效時返回錯誤碼來處理。但由於使用shiro後,會先執行shiro定義的過濾器,纔會執行自定義的過濾器,因此以前的方法行不通,參考了不少大大的博客,把個人處理方法貼上。javascript
1.自定義攔截器LoginFormFilter攔截器,繼承FormAuthenticationFilter類,在須要登陸而未登陸的請求都會執行onAccessDenied請求。css
package com.xxfy.demo.filter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.xxfy.demo.util.HttpUtils; public class LoginFormFilter extends FormAuthenticationFilter { private static final Logger log = LoggerFactory.getLogger(LoginFormFilter.class); @Override protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { HttpServletRequest httpServletRequest = (HttpServletRequest)request; HttpServletResponse httpServletResponse = (HttpServletResponse)response; if (isLoginRequest(request, response)) { if (isLoginSubmission(request, response)) { if (log.isTraceEnabled()) { log.trace("Login submission detected. Attempting to execute login."); } return executeLogin(request, response); } else { if (log.isTraceEnabled()) { log.trace("Login page view."); } //allow them to see the login page ;) return true; } } else { if (log.isTraceEnabled()) { log.trace("Attempting to access a path which requires authentication. Forwarding to the " + "Authentication url [" + getLoginUrl() + "]"); } //若是是Ajax請求,不跳轉登陸 if (HttpUtils.isAjax(httpServletRequest)){ System.out.println("ajax"); httpServletResponse.setStatus(401); } else { saveRequestAndRedirectToLogin(request, response); } return false; } } }
此處的onAccessDenied方法跟FormAuthenticationFilter基本相似,只是加了一段判斷是ajax請求的代碼 ,若是是ajax請求的話,直接返回錯誤碼,而不是跳轉登陸,由於若是是ajax請求的話,也沒法跳轉。java
2.shiro的配置類中配置攔截器。(此處使用了spring boot)jquery
package com.xxfy.demo.config; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import javax.servlet.Filter; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import com.xxfy.demo.filter.LoginFormFilter; /** * shiro配置類 * @author Administrator * */ @Configuration public class ShiroConfiguration { @Bean public SecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); return securityManager; } @Bean public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){ ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //攔截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); //配置退出過濾器,其中的具體的退出代碼Shiro已經替咱們實現了 filterChainDefinitionMap.put("/logout", "logout"); //靜態資源能夠不登陸訪問 /* filterChainDefinitionMap.put("/static/**", "anon");*/ filterChainDefinitionMap.put("/assets/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/unauth", "anon"); //filterChainDefinitionMap.put("/admin/index", "roles['admin']"); //全部請求都須要登陸才能夠訪問 filterChainDefinitionMap.put("/**", "authc"); //登陸請求 shiroFilterFactoryBean.setLoginUrl("/login"); //登陸成功跳轉的頁面 shiroFilterFactoryBean.setSuccessUrl("/admin/index"); Map<String,Filter> filters = new HashMap<String,Filter>(); Filter loginFilter = new LoginFormFilter(); filters.put("authc", loginFilter); //此處使用自定義的攔截器,autho默認使用FormAuthenticationFilter攔截器 shiroFilterFactoryBean.setFilters(filters); //沒有權限的頁面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauth"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public AuthorizingRealm myShiroRealm() { AuthorizingRealm myRealm = new MyShiroRealm(); myRealm.setCredentialsMatcher(customCredentialsMatcher()); return myRealm; } @Bean public CustomCredentialsMatcher customCredentialsMatcher() { CustomCredentialsMatcher customCredentialsMatcher = new CustomCredentialsMatcher(); customCredentialsMatcher.setHashAlgorithmName("MD5"); return customCredentialsMatcher; } }
此處的關鍵就是代碼就是這個:filters.put("authc", loginFilter);這裏使用第一步的過濾器,shiro默認使用FormAuthenticationFilter過濾器。web
3.前臺js中全局捕獲這個aja求返回的錯誤碼。ajax
$.ajaxSetup({ type: "POST", complete: function(jqXHR, textStatus){ switch (jqXHR.status){ case(500): alert("服務器系統內部錯誤"); break; case(401): $("#loginModal").modal("show"); break; case(403): alert("無權限執行此操做"); break; case(408): alert("請求超時"); break; default: alert("未知錯誤"); } }, success: function(data){ alert("操做成功"); } });
4.增長一步無關的一步,做爲本身的記錄,項目使用了jquery.datatable做爲數據展現,使用這種方法處理ajax請求時,若是session失效,進行查詢返回的確定就不會是json格式的數據,datatable會有一個自身的提示信息,須要把它去掉,此時只要在請求中增長error便可。spring
var table = $('#example').DataTable({ //開啓服務器模式 serverSide: true, //禁用搜索 searching: false, //禁用排序 ordering: false, //數據來源(包括處理分頁,排序,過濾) ,即url,action,接口,等等 ajax: { url : $("#contextPath").val() + "/admin/permissions/user/list", type:"post", data : function(d){ d.userId=$("#userId").val(); d.userName=$("#userName").val(); d.sex=$("#sex").val(); d.tel=$("#tel").val(); }, error:function(data) { } },
5.效果圖:apache