• 细说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

  • 相关阅读:
    019_Mac实用的图像备份工具
    016_把普通用户免秘钥加入root用户的几种方式
    027_磁盘维护命令du等
    026_lsof命令经验总结
    004_wireshark专题
    029_mount bind挂载
    023_nginx跨域问题
    mysql-5.7 group commit 详解
    二段式提交协议
    mysql-5.7 密码过期详解
  • 原文地址:https://www.cnblogs.com/nuccch/p/7843833.html
Copyright © 2020-2023  润新知