You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何安全过滤器链无UsernamePasswordAuthenticationFilter及链序疑问

关于Spring Security过滤器链的两个疑问

背景配置代码

http
        .cors().configurationSource(new CorsConfigurationSource() {
            @Override
            public CorsConfiguration getCorsConfiguration(HttpServletRequest request) {
                CorsConfiguration config = new CorsConfiguration();
                //todo: this should be set as environment variable
                config.setAllowedOrigins(Collections.singletonList("http://localhost"));
                config.setAllowedMethods(Collections.singletonList("*"));
                config.setAllowCredentials(true);
                config.setAllowedHeaders(Collections.singletonList("*"));
                config.setExposedHeaders(List.of("Authorization")); //todo: what does this mean?
                config.setMaxAge(3600L);
                return config;
            }
        })
        .and().csrf().disable()//todo: set csrf() in prod: ignoringRequestMatch
        .authorizeHttpRequests()
        .requestMatchers("/api/v1/auth/**").permitAll() //authorized all the target here
        .anyRequest().authenticated()

        .and().sessionManagement()
        .sessionCreationPolicy(SessionCreationPolicy.STATELESS) // do not store any state

        .and().authenticationProvider(authenticationProvider)
        .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

过滤器链日志

开启logging.level.org.springframework.security.web.FilterChainProxy=DEBUG后,输出日志如下:

Security filter chain: [
  DisableEncodeUrlFilter
  WebAsyncManagerIntegrationFilter
  SecurityContextHolderFilter
  HeaderWriterFilter
  CorsFilter
  LogoutFilter
  JwtAuthenticationFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  AuthorizationFilter
]

疑问

  1. 为何UsernamePasswordAuthenticationFilter.class不在过滤器链中?
  2. 日志打印的过滤器链顺序是否正确?若不正确,何处可获取正确顺序?

解答

1. UsernamePasswordAuthenticationFilter不在链中的原因

UsernamePasswordAuthenticationFilter是Spring Security为表单登录场景设计的过滤器,只有当你在配置中显式启用表单登录(比如调用.formLogin())时,它才会被自动加入过滤器链。

你的项目配置了SessionCreationPolicy.STATELESS(无状态会话),且采用JWT认证方案,完全不需要依赖表单登录流程,所以Spring Security不会自动添加这个过滤器。你用addFilterBefore指定它作为JWT过滤器的参照位置,只是利用它在默认过滤器链中的预设位置来确定JWT过滤器的插入点——即便它本身不在当前链中,Spring Security依然能识别这个位置并正确插入你的自定义JWT过滤器。

2. 过滤器链顺序正确性及获取方式

当前日志中的过滤器链顺序是正确的,完全适配无状态JWT认证的场景:

  • CorsFilter排在认证类过滤器之前,确保跨域请求先被处理
  • JwtAuthenticationFilter在AnonymousAuthenticationFilter之前,保证JWT认证优先执行,避免匿名认证提前生效
  • 后续的SessionManagementFilter、ExceptionTranslationFilter、AuthorizationFilter也都处于标准的执行位置

如果需要确认官方标准的过滤器链顺序,可以通过以下方式:

  • 查看Spring Security官方文档中关于过滤器链的章节
  • 在本地项目中调试FilterChainProxy类,查看默认过滤器的排序逻辑
  • 自定义过滤器时,使用addFilterBefore/addFilterAfter方法指定参照过滤器,Spring Security会按照默认的过滤器顺序规则自动放置你的自定义过滤器

内容的提问来源于stack exchange,提问作者Alex Teng

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:28:18