写在前面
我们知道,shiro框架在Java Web应用中使用时,本质上是通过filter方式集成的。
也就是说,它是遵循过滤器链规则的:filter的执行顺序与在web.xml中定义的顺序一致,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<filter> <filter-name>securityFilter</filter-name> <filter-class>com.lenovo.iot.devicemanager.filter.SecurityFilter</filter-class> </filter> <filter-mapping> <filter-name>securityFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml --> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <!-- Make sure any request you want accessible to Shiro is filtered. /* catches all --> <!-- requests. Usually this filter mapping is defined first (before all others) to --> <!-- ensure that Shiro works in subsequent filters in the filter chain: --> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
显然,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实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="filters"> <util:map> <entry key="shiroUserFilter" value-ref="shiroUserFilter" /> </util:map> </property> <property name="filterChainDefinitions"> <value> # some example chain definitions: # /admin/** = authc, roles[admin] # /docs/** = authc, perms[document:read] /**/login.do = anon /** = shiroUserFilter # more URL-to-FilterChain definitions here </value> </property> </bean> <!-- 定义扩展的filter实例 --> <bean id="shiroUserFilter" class="com.lenovo.iot.devicemanager.filter.ShiroUserFilter" /> |
【参考】
https://shiro.apache.org/web.html#Web-FilterChainDefinitions
转自:https://www.cnblogs.com/nuccch/p/7843833.html