首先了解下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
。
实现步骤:
- 定义一个
CustomShiroFilter
,所有自定义的Filter实现该接口
public interface CustomShiroFilter extends Filter {
}
- 定义一个
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());
}
}
- 引入该组件
@Configuration
@Import({ShiroFilterRegistrationBeanPostProcessor.class})
public class ShiroAutoConfiguration {
}
使用:后面可以随便的自定义Filter并直接声明为Bean了,不需要再去设置false了。
自定义一个Shiro过滤器继承CustomShiroFilter
public class MyShiroFilter extends AuthorizationFilter implements CustomShiroFilter {
...
}
网友评论