美文网首页
SpringBoot中Shiro自定义Filter 自动不注册为

SpringBoot中Shiro自定义Filter 自动不注册为

作者: xin_5457 | 来源:发表于2023-03-29 19:17 被阅读0次

    首先了解下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 {
       ...
    }
    

    相关文章

      网友评论

          本文标题:SpringBoot中Shiro自定义Filter 自动不注册为

          本文链接:https://www.haomeiwen.com/subject/zjofddtx.html