Spring基本认证测试配置问题

问题描述

我在 Spring Boot 项目中添加了基本身份验证,但遇到了一些意外错误

安全配置类:

@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);
    }
}

PostgresFacade 只是一个带有@Component 注解的层。映射器、存储库和服务也已正确注释。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)