細說shiro之自定義filter


寫在前面

我們知道,shiro框架在Java Web應用中使用時,本質上是通過filter方式集成的。
也就是說,它是遵循過濾器鏈規則的:filter的執行順序與在web.xml中定義的順序一致,如下所示:

<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實現

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

<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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM