细说shiro之自定义filter


写在前面

我们知道,shiro框架在Java Web应用中使用时,本质上是通过filter方式集成的。
也就是说,它是遵循过滤器链规则的:filter的执行顺序与在web.xml中定义的顺序一致,如下所示:


    securityFilter
    com.lenovo.iot.devicemanager.filter.SecurityFilter


    securityFilter
    /*




    shiroFilter
    org.springframework.web.filter.DelegatingFilterProxy
    
        targetFilterLifecycle
        true
    






    shiroFilter
    /*

显然,securityFilter定义在shiroFilter之前,那么securityFilter也是在shiroFilter之前被访问到。
根据这个原理,我们可以根据实际情况对shiro的filter进行扩展。
举个例子,shiro默认的org.apache.shiro.web.filter.authc.UserFilter会对请求进行过滤,在未登录时请求会被重定向到登录页面。
但是在API项目中,响应都是json格式,并不存在登录页面,此时就会返回404错误。

项目实践

在最新的项目中,前后端完全分离,通过API方式进行数据交换,并且在服务端集成了shiro进行权限控制,后端项目架构为:SpringMVC + Shiro。
为了在拦截那些未执行登录的请求时返回json格式的响应,对org.apache.shiro.web.filter.authc.UserFilter进行了扩展。
具体来说需要做2件事情:
1.扩展org.apache.shiro.web.filter.authc.UserFilter实现

public class ShiroUserFilter extends UserFilter {
	private static final Logger logger = LoggerFactory.getLogger(ShiroUserFilter.class);

	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
		if(logger.isErrorEnabled()) {
			logger.error("account need login for: {}",  ((HttpServletRequest)request).getServletPath());
		}

        // 请求被拦截后直接返回json格式的响应数据
		response.getWriter().write(JsonResp.getJsonRespError(JsonResp.SC_NOT_LOGINED, "account not logined").toString());
		response.getWriter().flush();
		response.getWriter().close();
		return false;
	}
}

2.在spring中定义并使用自定义扩展的filter


    
    
        
            
        
    
    
        
            # some example chain definitions:
            # /admin/** = authc, roles[admin]
            # /docs/** = authc, perms[document:read]
            /**/login.do = anon
            /** = shiroUserFilter
            # more URL-to-FilterChain definitions here
        
    




【参考】
https://shiro.apache.org/web.html#Web-FilterChainDefinitions