springSecurityFilterChain has 3 filter chains all matching any request in Integration test, but there should only be one

huangapple go评论98阅读模式
英文:

springSecurityFilterChain has 3 filter chains all matching any request in Integration test, but there should only be one

问题

我为我的Spring Boot应用编写了基于JWT的身份验证流程。它向过滤器链添加了两个过滤器:JwtAuthenticationFilter和JwtAuthorizationFilter。将它们添加到链中是在我的SecurityConfig类中完成的:

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity.cors().and().csrf().disable()
            .authorizeRequests()
            .antMatchers(H2CONSOLE_LOCATION).permitAll()
            .antMatchers(HttpMethod.POST, REGISTER_URL).permitAll()
            .antMatchers(HttpMethod.POST, LOGIN_URL).permitAll()
            .anyRequest().authenticated()
            .and()
            .addFilter(new JwtAuthenticationFilter(authenticationManager(), tokenService))
            .addFilter(new JwtAuthorizationFilter(authenticationManager(), tokenService))
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

这是我集成测试的设置(使用Groovy编写,使用Spock):

@SpringBootTest(classes = CarshareUsersApplication.class)
@TestPropertySource(locations = "classpath:application-local.properties")
@ActiveProfiles("local")
@WebAppConfiguration
@ExtendWith(SpringExtension.class)
class UserRestControllerIT extends Specification {

    @Autowired
    ObjectMapper mapper

    private MockMvc mvc

    @Autowired
    private WebApplicationContext context

    @Autowired
    private Filter springSecurityFilterChain;

    def setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .addFilters(springSecurityFilterChain)
                .build()
    }
}

然而,当我使用我的mockMvc发送请求时,过滤器没有被使用。我在过滤器和SecurityConfig中放置了断点,但只有SecurityConfig中的断点被触发。

当检查我的mockMVC时,我发现我的springSecurityFilterChain实际上包含了3个过滤器链,但它们都匹配任何请求。只有一个(第二个)包含了我的自定义过滤器。请参阅下面的屏幕截图以查看内容:

springSecurityFilterChain has 3 filter chains all matching any request in Integration test, but there should only be one

查看调试日志确认了我的猜想:

Request received for POST '/login':

org.springframework.mock.web.MockHttpServletRequest@10ea1754

servletPath:
pathInfo:/login
headers: 
Content-Type: application/json
Content-Length: 170


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]

我不明白第一个和第三个过滤器链是从哪里来的,以及为什么它们都匹配所有内容。有人可以给我一些关于如何使用仅包含我的自定义过滤器的一个链的指导吗?

英文:

I wrote a JWT-based authentication flow for my Spring boot application. It adds two Filters to the chain: a JwtAuthenticationFilter and a JwtAuthorizationFilter. Adding them to the chain happens in my SecurityConfig class:

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.cors().and().csrf().disable()
                .authorizeRequests()
                .antMatchers(H2CONSOLE_LOCATION).permitAll()
                .antMatchers(HttpMethod.POST, REGISTER_URL).permitAll()
                .antMatchers(HttpMethod.POST, LOGIN_URL).permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager(), tokenService))
                .addFilter(new JwtAuthorizationFilter(authenticationManager(), tokenService))
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

This is the setup for my Integration test (written in groovy using spock):

@SpringBootTest(classes = CarshareUsersApplication.class)
@TestPropertySource(locations = "classpath:application-local.properties")
@ActiveProfiles("local")
@WebAppConfiguration
@ExtendWith(SpringExtension.class)
class UserRestControllerIT extends Specification {

    @Autowired
    ObjectMapper mapper

    private MockMvc mvc

    @Autowired
    private WebApplicationContext context

    @Autowired
    private Filter springSecurityFilterChain;

    def setup() {
        mvc = MockMvcBuilders
                .webAppContextSetup(context)
                .addFilters(springSecurityFilterChain)
                .build()
    }

However, when I post a request using my mockMvc, the filters aren't used. I put breakpoints in the filters and in the SecurityConfig, but only the ones in the SecurityConfig get hit.

When inspecting my mockMVC I saw that my springSecurityFilterChain actually holds 3 filterChains, but they all match any request. Only one (the second one) holds my custom filters. See the screenshot below for the contents:

springSecurityFilterChain has 3 filter chains all matching any request in Integration test, but there should only be one

Looking at the debug log confirms my suspicion:

Request received for POST '/login':

org.springframework.mock.web.MockHttpServletRequest@10ea1754

servletPath:
pathInfo:/login
headers: 
Content-Type: application/json
Content-Length: 170


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]

I don't get where the first and third filterchain come from, and why they all match everything. Can anyone give me some pointers on how to work with only one chain that holds my custom filters?

答案1

得分: 2

我找到了另外两个链的来源:我有一个TestSecurityConfiguration和另一个SecurityConfiguration,当我仍在使用基本身份验证时,它们都被加载了。这与我在帖子中提到的SecurityConfig一起,共有3个WebSecurityConfigurerAdapters,因此有3个链。

我通过深入研究Spring Security源代码找到了这一点,查找了将securityChains添加到最终配置的位置。这引导我进入了WebSecurity类和securityFilterChainBuilders属性。快速查找"find usages"让我找到了addSecurityFilterChainBuilder方法。在那里设置断点,然后查看调用堆栈,我找到了我的3个SecurityConfigurerAdapters。

这绝对是一个有趣的深度研究 springSecurityFilterChain has 3 filter chains all matching any request in Integration test, but there should only be one

英文:

I found where the other two chains came from: I had one TestSecurityConfiguration and another SecurittyConfiguration from when I was still using basic auth that were both being loaded. That together with the SecurityConfig from my post makes 3 WebSecurityConfigurerAdapters, resulting in 3 chains.

I found this by diving into the Spring Security source code, looking for where securityChains are added to the final configuration. This led me to the WebSecurity class and the securityFilterChainBuilders property. A quick "find usages" led me to the addSecurityFilterChainBuilder method. A breakpoint there and then looking through the call stack led me to my 3 SecurityConfigurerAdapters.

An interesting deep dive to be sure springSecurityFilterChain has 3 filter chains all matching any request in Integration test, but there should only be one

答案2

得分: 0

@Autowired
private WebApplicationContext context

@Autowired
private Filter springSecurityFilterChain;

def setup() {
    mvc = MockMvcBuilders
            .webAppContextSetup(context)
            .addFilters(springSecurityFilterChain)
            .build()
}

根据我的理解,上下文应该已经初始化了一个过滤器链,而你又添加了一个。这至少可以解释为什么有一个多余的。不清楚为什么还有另一个。

你可以比较`springSecurityFilterChain`的对象ID与你的调试器中的过滤器链列表吗?
英文:
@Autowired
private WebApplicationContext context

@Autowired
private Filter springSecurityFilterChain;

def setup() {
    mvc = MockMvcBuilders
            .webAppContextSetup(context)
            .addFilters(springSecurityFilterChain)
            .build()
}

To my understanding the context would be already initialized with a filter chain and you add one more. That would explain at least one superfluous. No idea why there is another one.

Could you compare object id of springSecurityFilterChain with the list of filter chains in your debugger?

huangapple
  • 本文由 发表于 2020年7月31日 23:12:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/63194540.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定