Spring Boot 3 Kotlin自定义SecurityFilterChain未生效问题及解决
Spring Boot 3 + Kotlin 自定义SecurityFilterChain未加载导致403 CSRF错误的解决
问题现象
在Spring Boot 3 + Kotlin项目中,已完成以下配置:
- 编写
SecurityConfig禁用CSRF,并允许/api/**路径匿名访问 - 实现
EventController提供POST接口 - 用
@WebMvcTest编写接口测试
但执行测试或手动请求接口时,均返回403 Forbidden,日志提示CSRF校验失败,调试后确认自定义的SecurityFilterChain Bean并未被加载。
根本原因
@WebMvcTest是Spring MVC层的切片测试注解,默认仅扫描加载控制器类及Spring MVC相关组件,不会自动导入@Configuration标注的配置类(如SecurityConfig)。此时Spring Security会启用默认配置,默认开启CSRF校验,导致POST请求被拦截返回403。
解决办法
在测试类EventControllerTest上添加@Import(SecurityConfig::class),显式将自定义安全配置导入到测试上下文中,确保自定义的SecurityFilterChain生效。
相关代码及项目信息
控制器代码
data class EventRequest( val name: String ) data class EventResponse( val name: String ) @RestController @RequestMapping("/api/v1/events") class EventController { @PostMapping @ResponseStatus(HttpStatus.CREATED) fun addEvent(@RequestBody event: EventRequest): EventResponse { return EventResponse(name = event.name) } }
安全配置代码
@Configuration @EnableWebSecurity(debug = true) class SecurityConfig { @Bean @Throws(Exception::class) fun customSecurityFilterChain(http: HttpSecurity): SecurityFilterChain { http .csrf().disable() .formLogin().disable() .authorizeHttpRequests().requestMatchers("/api/**").permitAll() return http.build() } }
修改后的测试代码
@WebMvcTest @Import(SecurityConfig::class) // 新增导入配置类 class EventControllerTest { @Autowired private lateinit var mockMvc: MockMvc @Autowired private lateinit var objectMapper: ObjectMapper @Test fun `add event successfully`() { val event = EventRequest(name = "My event") val body = objectMapper.writeValueAsString(event) this.mockMvc .perform( post("/api/v1/events") .content(body) .contentType(MediaType.APPLICATION_JSON)) .andExpect(status().isCreated) } }
项目结构
. ├── main │ ├── kotlin │ │ └── dev │ │ └── nystrom │ │ └── happyevents │ │ ├── HappyEventsApplication.kt │ │ ├── config │ │ │ └── SecurityConfig.kt │ │ └── controllers │ │ └── EventController.kt │ └── resources │ ├── application.properties │ ├── db │ │ └── changelog │ │ └── db.changelog-master.yaml │ ├── static │ └── templates └── test └── kotlin └── dev └── nystrom └── happyevents ├── HappyEventsApplicationTests.kt └── controllers └── EventControllerTest.kt
build.gradle.kts配置
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("org.springframework.boot") version "3.0.5" id("io.spring.dependency-management") version "1.1.0" kotlin("jvm") version "1.8.10" kotlin("plugin.spring") version "1.8.10" } group = "dev.nystrom" version = "0.0.1-SNAPSHOT" java.sourceCompatibility = JavaVersion.VERSION_17 repositories { mavenCentral() } dependencies { implementation("org.springframework.boot:spring-boot-starter-data-jdbc") implementation("org.springframework.boot:spring-boot-starter-oauth2-client") implementation("org.springframework.boot:spring-boot-starter-security") implementation("org.springframework.boot:spring-boot-starter-thymeleaf") implementation("org.springframework.boot:spring-boot-starter-web") implementation("com.fasterxml.jackson.module:jackson-module-kotlin") implementation("org.jetbrains.kotlin:kotlin-reflect") implementation("org.liquibase:liquibase-core") implementation("org.springframework.session:spring-session-core") implementation("org.thymeleaf.extras:thymeleaf-extras-springsecurity6") implementation("org.springframework.boot:spring-boot-starter-actuator") developmentOnly("org.springframework.boot:spring-boot-devtools") runtimeOnly("org.postgresql:postgresql") testImplementation("org.springframework.boot:spring-boot-starter-test") testImplementation("org.springframework.security:spring-security-test") } tasks.withType<KotlinCompile> { kotlinOptions { freeCompilerArgs = listOf("-Xjsr305=strict") jvmTarget = "17" } } tasks.withType<Test> { useJUnitPlatform() }
HappyEventsApplication.kt启动类
package dev.nystrom.happyevents import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication @SpringBootApplication class HappyEventsApplication fun main(args: Array<String>) { runApplication<HappyEventsApplication>(*args) }
内容的提问来源于stack exchange,提问作者Richard N.
相关产品推荐
相关产品推荐

