SpringBoot中Shiro自定義Filter 自動不注冊為全局Application Filter

首先了解下SpringBoot中三種Filter注冊方式:

  • 直接使用@WebFilter 注解
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("-----doFilter-----");
        chain.doFilter(request, response);
    }
}
  • 聲明為Bean
    @Bean
    public MyFilter myFilter() {
        return new MyFilter();
    }
  • 定義FilterRegistrationBean
    @Bean
    FilterRegistrationBean<MyFilter> myFilterRegistrationBean() {
        FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<>();
        bean.setFilter(new MyFilter());
        bean.setOrder(-1);
        bean.setUrlPatterns(Arrays.asList("/*"));
        return bean;
    }

以上三種聲明后,都會在ServletContextInitializerBeans中進行初始化。

    public ServletContextInitializerBeans(ListableBeanFactory beanFactory,
            Class<? extends ServletContextInitializer>... initializerTypes) {
        this.initializers = new LinkedMultiValueMap<>();
        this.initializerTypes = (initializerTypes.length != 0) ? Arrays.asList(initializerTypes)
                : Collections.singletonList(ServletContextInitializer.class);
        //初始化ServletContextInitializer類型的Bean,例如:FilterRegistrationBean
        addServletContextInitializerBeans(beanFactory);
        //初始化直接聲明為Bean的Filter,如果上一步已經識別到了,該步驟就會忽略掉該Filter。
        addAdaptableBeans(beanFactory);
        List<ServletContextInitializer> sortedInitializers = this.initializers.values().stream()
                .flatMap((value) -> value.stream().sorted(AnnotationAwareOrderComparator.INSTANCE))
                .collect(Collectors.toList());
        this.sortedList = Collections.unmodifiableList(sortedInitializers);
        logMappings(this.initializers);
    }

Shiro中自定義Filter

Shiro自定義Filter后需要注冊到ShiroFilterFactoryBean 中。如果直接通過@Bean聲明后再加入,這個Filter將會被Spring接管,然后自動注冊到ApplicationFilter,導致被重復執行。
有兩種方式避免:

  • 注冊到ShiroFilterFactoryBean直接new出來,這樣Spring不會接管該filter,
filters.put("myFilter", new MyShiroFilter());
  • 使用@Bean聲明后,在通過FilterRegistrationBean設置不加載到ApplicationFilter
    @Bean
    public MyShiroFilter myShiroFilter() {
        return new MyShiroFilter();
    }

    @Bean
    public FilterRegistrationBean<MyShiroFilter> captchaAuthcRegistrationBean(MyShiroFilter filter) {
        FilterRegistrationBean<MyShiroFilter> registration = new FilterRegistrationBean<>(filter);
        //設置為不注冊為ApplicationFilter
        registration.setEnabled(false);
        return registration;
    }

如何自動識別Shiro自定義Filter,不自動注冊ApplicationFilter

有時候寫通用模塊的時候,需要自動發現Shiro自定義Filter,并自動注冊。自動發現可以通過聲明為Bean。
但是聲明為Bean之后就會被注冊為ApplicationFilter。難道每次都要寫個FilterRegistrationBean來防止注冊為ApplicationFilter

可以通過BeanFactoryPostProcessor來擴展實現,也就是找到Shiro自定義Filter,然后自動注冊一個FilterRegistrationBean
實現步驟:

  1. 定義一個CustomShiroFilter,所有自定義的Filter實現該接口
public interface CustomShiroFilter extends Filter {
}
  1. 定義一個 ShiroFilterRegistrationBeanPostProcessor 組件
public class ShiroFilterRegistrationBeanPostProcessor implements BeanFactoryPostProcessor {

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
        //找到所有自定義的ShiroFilter,并注冊FilterRegistrationBean
        String[] beanNames = beanFactory.getBeanNamesForType(CustomShiroFilter.class);
        for (String beanName : beanNames) {
            registerFilterRegistrationBean(defaultListableBeanFactory, beanName);
        }
    }

    private static void registerFilterRegistrationBean(DefaultListableBeanFactory beanFactory, String beanName) {
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(FilterRegistrationBean.class);
        beanDefinitionBuilder.addPropertyReference("filter", beanName);
        beanDefinitionBuilder.addPropertyValue("enabled", false);
        beanFactory.registerBeanDefinition(beanName + "FilterRegistrationBean",
                beanDefinitionBuilder.getRawBeanDefinition());
    }
}
  1. 引入該組件
@Configuration
@Import({ShiroFilterRegistrationBeanPostProcessor.class})
public class ShiroAutoConfiguration {
}

使用:后面可以隨便的自定義Filter并直接聲明為Bean了,不需要再去設置false了。
自定義一個Shiro過濾器繼承CustomShiroFilter

public class MyShiroFilter extends AuthorizationFilter implements CustomShiroFilter {
   ...
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容