You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 16:27:29