如何在@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();
禁用它
这应该可以帮助您解决问题。
为什么我会收到以下测试的 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();
这应该可以帮助您解决问题。