Java Spring基本身份验证测试配置问题
我将基本身份验证添加到Spring Boot项目中,遇到了一些意外错误 安全配置类:Java Spring基本身份验证测试配置问题,java,spring-boot,spring-webflux,basic-authentication,testcontainers,Java,Spring Boot,Spring Webflux,Basic Authentication,Testcontainers,我将基本身份验证添加到Spring Boot项目中,遇到了一些意外错误 安全配置类: @EnableWebSecurity public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter { @Value("${myapp.user}") private String user; @Value("${myapp.password}&quo
@EnableWebSecurity
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Value("${myapp.user}")
private String user;
@Value("${myapp.password}")
private String password;
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.antMatcher("/postgres/**")
.authorizeRequests(authorize ->
authorize
.anyRequest()
.hasRole("USER"))
.httpBasic(Customizer.withDefaults())
.csrf().disable();
}
@Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser(user).password(passwordEncoder().encode(password))
.authorities("ROLE_USER");
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
我向build.gradle文件添加了2个依赖项:
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.4.4'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.4.4'
build.gradle:
dependencies {
developmentOnly "org.springframework.boot:spring-boot-devtools"
implementation "org.springframework.boot:spring-boot-starter-webflux"
implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation 'io.micrometer:micrometer-registry-prometheus'
implementation 'org.springframework.data:spring-data-r2dbc:1.1.4.RELEASE'
implementation 'org.mapstruct:mapstruct:1.3.1.Final'
def springFoxVersion = "3.0.0"
implementation "io.springfox:springfox-boot-starter:$springFoxVersion"
implementation "io.springfox:springfox-swagger2:$springFoxVersion"
implementation "io.springfox:springfox-swagger-ui:$springFoxVersion"
implementation "io.springfox:springfox-spring-webflux:$springFoxVersion"
implementation 'net.logstash.logback:logstash-logback-encoder:6.4'
compileOnly 'org.projectlombok:lombok'
compile 'javax.persistence:javax.persistence-api:2.2'
runtimeOnly 'io.r2dbc:r2dbc-postgresql'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.3.1.Final'
annotationProcessor 'org.projectlombok:lombok'
testImplementation "org.springframework.boot:spring-boot-starter-test"
testImplementation 'org.springframework.cloud:spring-cloud-starter:2.2.5.RELEASE'
testImplementation "io.projectreactor:reactor-test"
def junitJupiterVersion = "5.4.2"
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitJupiterVersion"
testImplementation "org.junit.jupiter:junit-jupiter-params:$junitJupiterVersion"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitJupiterVersion"
def testContainersVersion = "1.15.0"
testImplementation "org.testcontainers:postgresql:$testContainersVersion"
testImplementation "org.testcontainers:r2dbc:$testContainersVersion"
testImplementation "org.testcontainers:testcontainers:$testContainersVersion"
testImplementation "org.testcontainers:junit-jupiter:$testContainersVersion"
testImplementation 'com.google.truth:truth:1.0.1'
def mockitoVersion = "3.5.7"
testImplementation "org.mockito:mockito-core:$mockitoVersion"
testImplementation "org.mockito:mockito-junit-jupiter:$mockitoVersion"
}
我的测试班:
@SpringBootTest
@Testcontainers
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@AutoConfigureWebTestClient
class MyApplicationContainerTest {
@Autowired
PostgresController postgresController;
@Autowired
WebTestClient webTestClient;
@Autowired
EventRepository eventRepository;
@DynamicPropertySource
static void registerDynamicProperties(DynamicPropertyRegistry registry) {
registry.add("spring.r2dbc.url", () -> "r2dbc:tc:postgresql:///test?TC_IMAGE_TAG=13.1");
}
@TestConfiguration
static class TestConfig {
@Bean
public ConnectionFactoryInitializer initializer(ConnectionFactory connectionFactory) {
final ConnectionFactoryInitializer initializer = new ConnectionFactoryInitializer();
initializer.setConnectionFactory(connectionFactory);
final CompositeDatabasePopulator populator = new CompositeDatabasePopulator();
populator.addPopulators(new ResourceDatabasePopulator(new ClassPathResource("schema.sql")));
initializer.setDatabasePopulator(populator);
return initializer;
}
}
@AfterEach
public void afterEach() {
eventRepository.deleteAll().block(Duration.ofSeconds(5));
}
@Test
void contextShouldLoad() {
assertThat(postgresController).isNotNull();
}
@Test
void shouldInsertEventsIntoDatabase() {
final Event event = Event.builder()
.userId(1L)
.build();
webTestClient
.post()
.uri("/postgres/save_event")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.body(Mono.just(event), Event.class)
.exchange()
.expectStatus().isOk()
eventRepository.findAll().take(1).as(StepVerifier::create)
.expectNext(EventEntity.builder()
.userId(1L)
.build())
.verifyComplete();
}
当我这样做的时候,我已经在工作的测试中断了:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.test.web.reactive.server.WebTestClient' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
我期待的是某种身份验证错误,而不是bean。
通过使用不同的测试类注释,我能够绕过这个问题:
@AutoConfigureWebTestClient
@ComponentScan("mypackage")
@Testcontainers
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
@WebFluxTest(value = PostgresController.class)
@ContextConfiguration(classes = {
PostgresFacade.class,
PostgresController.class,
EventService.class,
EventRepository.class,
EventMapper.class})
这会导致另一个错误:
Caused by: org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'requestDataValueProcessor' org/springframework/security/config/annotation/web/reactive/WebFluxSecurityConfiguration.class
org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.class
这可以通过以下方法解决:
spring.main.allow-bean-definition-overriding=true
最终导致我无法用现有知识修复的错误:
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'eventRepository' defined in mypackage.repository.EventRepository defined in @EnableR2dbcRepositories declared on MyApp: Cannot resolve reference to bean 'r2dbcDatabaseClient' while setting bean property 'databaseClient'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'r2dbcDatabaseClient' available
...
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'r2dbcDatabaseClient' available
结论
我期待着一个身份验证错误,我可以用@WithMockUser注释之类的东西来克服,但是我遇到了一个关于bean和依赖项的错误循环。
有人能帮我指出我犯了什么错误以及应该做些什么来正确运行测试吗
控制器看起来像:
@RestController
@RequestMapping("postgres/")
@Timed
public class PostgresController {
private final PostgresFacade postgresFacade;
@Autowired
public PostgresController(PostgresFacade postgresFacade) {
this.postgresFacade = postgresFacade;
}
@PostMapping(path = "/save_event)
public Mono<EventDto> saveEvent(@RequestBody EventDto event) {
return postgresFacade.saveEvent(event);
}
}
@RestController
@请求映射(“postgres/”)
@定时
公共类PostgresController{
私人最终博士后学院博士后学院;
@自动连线
公共PostgresController(PostgresFacade PostgresFacade){
this.postgresFacade=postgresFacade;
}
@PostMapping(path=“/save\u事件)
公共Mono saveEvent(@RequestBody EventDto event){
返回postgresFacade.saveEvent(事件);
}
}
PostgresFacade只是一个带有@Component Annotation的层。映射器、存储库和服务也被正确注释。您正在使用WebFlux,但已为Spring MVC配置了Spring安全性。包含Spring Web和Spring WebFlux会导致问题。设置正确的Sprign安全性(对于WebFlux而不是MVC)并删除SpringWeb依赖项。