Spring Security中AuthenticationFilter配置报错及编译无错原因问询
问题:Spring Security中使用AuthenticationFilter.class为何仅启动时报错?
问题场景
我在Spring Security配置中尝试执行如下代码:
http .csrf(AbstractHttpConfigurer::disable) .cors(AbstractHttpConfigurer::disable) .addFilterAfter(CoustomAuthCheckFilter, AuthenticationFilter.class)
预期服务能正常启动,却出现如下报错:
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration': Unsatisfied dependency expressed through method 'setFilterChains' parameter 0: Error creating bean with name 'filterChain' defined in class path resource [com/wincubemkt/mediagw/global/config/SecurityConfig.class]: Failed to instantiate [org.springframework.security.web.SecurityFilterChain]: Factory method 'filterChain' threw exception with message: The Filter class org.springframework.security.web.authentication.AuthenticationFilter does not have a registered order at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.resolveMethodArguments(AutowiredAnnotationBeanPostProcessor.java:895) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:848) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:145) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:508) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1439) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:599) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:337) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:335) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) ~[spring-beans-6.1.11.jar:6.1.11] at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:971) ~[spring-context-6.1.11.jar:6.1.11] at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:625) ~[spring-context-6.1.11.jar:6.1.11] at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146) ~[spring-boot-3.3.2.jar:3.3.2] at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) ~[spring-boot-3.3.2.jar:3.3.2] at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) ~[spring-boot-3.3.2.jar:3.3.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:335) ~[spring-boot-3.3.2.jar:3.3.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1363) ~[spring-boot-3.3.2.jar:3.3.2] at org.springframework.boot.SpringApplication.run(SpringApplication.java:1352) ~[spring-boot-3.3.2.jar:3.3.2] at com.wincubemkt.mediagw.MEDIAGWApplication.main(MEDIAGWApplication.java:11) ~[main/:na] at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) ~[na:na] at java.base/java.lang.reflect.Method.invoke(Method.java:580) ~[na:na] at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:50) ~[spring-boot-devtools-3.3.2.jar:3.3.2]
将代码修改为如下形式后,服务可正常启动:
http .csrf(AbstractHttpConfigurer::disable) .cors(AbstractHttpConfigurer::disable) .addFilterAfter(CoustomAuthCheckFilter, UsernamePasswordAuthenticationFilter.class) ...
我的疑问是:AuthenticationFilter.class并非通常直接使用的具体过滤器,为何使用它时编译器不报错,仅在服务启动时才出现错误?
原因分析
- 编译阶段仅做类型校验:
addFilterAfter方法的参数只要求传入一个Class<? extends Filter>类型的对象,AuthenticationFilter确实实现了Filter接口,所以编译器只会校验类型是否合法,不会验证该过滤器是否在Spring Security的过滤器链中存在预定义的执行顺序。 - 启动阶段才校验过滤器链配置:Spring Security在启动构建
SecurityFilterChain时,会检查每个过滤器的注册顺序。AuthenticationFilter是Spring Security提供的用于扩展的基础类,并非默认过滤器链中预注册的过滤器,没有被赋予默认的顺序值;而UsernamePasswordAuthenticationFilter是默认过滤器链中的核心组件,自带Spring Security预定义的顺序,因此启动时会抛出The Filter class ... does not have a registered order的错误。 - 设计定位限制:
AuthenticationFilter的设计目的是作为子类扩展的基类,本身并不直接加入默认过滤器链。如果要使用它,需要自定义子类并手动指定执行顺序,或者通过配置将其注册到过滤器链中。直接将它作为addFilterAfter的参照类,Spring无法找到对应的顺序配置,导致启动失败。
内容的提问来源于stack exchange,提问作者minjun
相关产品推荐
相关产品推荐

