咱們知道,shiro框架在Java Web應用中使用時,本質上是經過filter方式集成的。
也就是說,它是遵循過濾器鏈規則的:filter的執行順序與在web.xml中定義的順序一致,以下所示:html
<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錯誤。java
在最新的項目中,先後端徹底分離,經過API方式進行數據交換,而且在服務端集成了shiro進行權限控制,後端項目架構爲:SpringMVC + Shiro。
爲了在攔截那些未執行登陸的請求時返回json格式的響應,對org.apache.shiro.web.filter.authc.UserFilter進行了擴展。
具體來講須要作2件事情:
1.擴展org.apache.shiro.web.filter.authc.UserFilter實現web
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中定義並使用自定義擴展的filterspring
<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-FilterChainDefinitionsapache