最近在学习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