Spring Boot环境下自定义shiro过滤器会过滤所有的url的问题

发布时间 2023-10-29 17:00:12作者: TimQiu

问题起因:

在Shiro配置类中定义如下:

@Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(ShiroAuthFilter shiroAuthFilter, SecurityManager securityManager) {
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        Map<String, Filter> filters = new HashMap<>(1);
        filters.put("shiroAuthFilter", shiroAuthFilter);
        factoryBean.setFilters(filters);
        factoryBean.setSecurityManager(securityManager);

        // 必须使用LinkedHashMap来保持有序性
        Map<String, String> filterMap = new LinkedHashMap<>();
        // anon: Filter that allows access to a path immeidately without performing security checks of any kind.
        filterMap.put("/swagger*/**", "anon");
        filterMap.put("/v2/api-docs", "anon");
        filterMap.put("/test/**", "anon");
        filterMap.put("/**", "shiroAuthFilter");
        System.out.println(filterMap.keySet());
        factoryBean.setFilterChainDefinitionMap(filterMap);

        return factoryBean;
    }

可以发现,我正确地使用了LinkedHashMap作为存储集合并把filterMap.put("/**", "shiroAuthFilter");放在了最后,按道理是最后一个过滤的,但结果是访问如/test/2/swagger/123这样的路径也会被自定义的shiroAuthFilter过滤器拦截

在网上搜索大量资料后发现SpringBoot会自动注册shiroAuthFilter为全局过滤器,即使只使用了@Component注解。

顺序如下:

2023-10-29 16:29:18.810 DEBUG 24532 --- [  restartedMain] o.s.b.w.s.ServletContextInitializerBeans : 
Mapping filters: 
filterRegistrationBean urls=[/*] order=2147483647, 
com.timqiu.ocos.filter.XssFilter urls=[/*] order=2147483647, 
characterEncodingFilter urls=[/*] order=-2147483648, 
formContentFilter urls=[/*] order=-9900, 
requestContextFilter urls=[/*] order=-105, 
shiroAuthFilter urls=[/*] order=2147483647,
shiroFilterFactoryBean urls=[/*] order=2147483647

顺便说下如何开启这个日志:

logging:
  level:
    web: debug

可以看到,shiroAuthFiltershiroFilterFactoryBean之前,匹配路径为/*,并且优先级还和shiroFilterFactoryBean一样!!!!

也就是说,不管请求怎么走,都会先经过shiroAuthFilter过滤器而不会走shiroFilterFactoryBean过滤器!!!

那怎么解决呢?当然是禁用掉该过滤器的自动注册功能!!

在SpringBoot官方文档中就说的很清楚如何禁用过滤器的自动注册功能:

Disable Registration of a Servlet or Filter

As described earlier, any Servlet or Filter beans are registered with the servlet container automatically. To disable registration of a particular Filter or Servlet bean, create a registration bean for it and mark it as disabled, as shown in the following example:

@Configuration(proxyBeanMethods = false)
public class MyFilterConfiguration {

    @Bean
    public FilterRegistrationBean<MyFilter> registration(MyFilter filter) {
        FilterRegistrationBean<MyFilter> registration = new FilterRegistrationBean<>(filter);
        registration.setEnabled(false);
        return registration;
    }

}

链接如下:Spring Boot Reference Documentation

禁用之后,再次查看日志,发现没有shiroAuthFilter这一项了,正常访问没有被过滤的网址,问题解决。