如何在@WebFluxTest 中禁用 csrf 保护?

How to disable crsf protection in @WebFluxTest?

为什么我会收到以下测试的 403 FORBIDDEN

@RestController
public class MyServlet {
    @PostMapping("/")
    public Mono<String> accept(Authentication authentication) {}
}


@WebFluxTest(MyServlet.class)
@WithMockUser
public class MyServletTest {
    @Autowired
    private WebTestClient webClient;

    @Test
    public void test() {
        webClient.post().url("/")
            .exchange()
            .expectStatus().isOk();
    }
}

结果:

java.lang.AssertionError: Status expected:<200 OK> but was:<403 FORBIDDEN>

> POST /
> WebTestClient-Request-Id: [1]
> Content-Type: [application/json]

No content

< 403 FORBIDDEN Forbidden
< Content-Type: [text/plain]
< Cache-Control: [no-cache, no-store, max-age=0, must-revalidate]
< Pragma: [no-cache]
< Expires: [0]
< X-Content-Type-Options: [nosniff]
< X-Frame-Options: [DENY]
< X-XSS-Protection: [1 ; mode=block]
< Referrer-Policy: [no-referrer]

CSRF Token has been associated to this client

据我所知,@WebFluxTest 禁用了 csrf。那么它为什么会抱怨呢?

webClient.mutateWith(csrf()).post()...;

发生这种情况是因为您的类路径中可能有 spring-boot-starter-security。您需要创建一个配置:

@Configuration
@EnableWebFluxSecurity
public class WebFluxSecurityConfig {
  @Bean
  public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
    return http.csrf().disable().build();
  }
}

并使用

将其导入到您的测试中
@Import(WebFluxSecurityConfig.class)

显然 @WebFluxTest 中默认未加载 SecurityConfig。

我在这里找到了解决方案:https://github.com/spring-projects/spring-boot/issues/16088

您可以使用 @SpringBootTest@AutoConfigureWebTestClient 一起加载默认配置,以配置和注入测试客户端。将两个注释都放在你的测试中 class.

根本原因是因为您的类路径中有 spring-security 依赖项。

在我的例子中,它是 Spring 响应式应用程序,安全配置是通过创建一个 bean 并用 @EnableWebFluxSecurity

注释来应用的
  @Configuration
   @EnableWebFluxSecurity
   public class SecurityConfig {
   
@Bean
  public SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {
    http.oauth2Client();
    return http.authorizeExchange().anyExchange().permitAll().and().build();
  }
}

因此,默认情况下 Spring 安全配置的性质,CSRF 将被启用。 现在我们必须根据问题 “您的应用程序是否需要启用 CSRF?” 来决定解决方案 如果答案是肯定的那么你的测试也应该使用 csrf 这可以通过 webClient.mutateWith(csrf()).post() 如果不需要启用csrf,则通过http.authorizeExchange().anyExchange().permitAll().and().csrf().disable().build();

禁用它

这应该可以帮助您解决问题。