知識庫 / Spring / Spring Boot RSS 訂閱

Spring Boot 集成測試中的 Spring Security 整合

Spring Boot,Spring Security,Testing
HongKong
5
01:41 PM · Dec 06 ,2025

1. 引言

能夠執行集成測試而無需獨立的集成環境,對於任何軟件棧來説都是一項寶貴的特性。 Spring Boot 與 Spring Security 的無縫集成使得測試與安全層交互的組件變得簡單。

在本快速教程中,我們將探索使用 @MockMvcTest@SpringBootTest 來執行具有安全功能的集成測試。

2. 依賴項

以下是我們示例所需的依賴項:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-test</artifactId>
    <scope>test</scope>
</dependency>

以下 starter 包,即 spring-boot-starter-webspring-boot-starter-securityspring-boot-starter-test,使我們能夠訪問 Spring MVC、Spring Security 以及 Spring Boot 測試實用工具。

此外,我們還將引入 spring-security-test,以便訪問我們即將使用的 @WithMockUser 註解。

3. Web 安全配置

我們的 Web 安全配置將非常簡單。只有經過身份驗證的用户才能訪問與 /private/** 匹配的路徑。與 /public/** 匹配的路徑將對任何用户開放:

@Configuration
public class WebSecurityConfigurer {

    @Bean
    public InMemoryUserDetailsManager userDetailsService(PasswordEncoder passwordEncoder) {
        UserDetails user = User.withUsername("spring")
            .password(passwordEncoder.encode("secret"))
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.authorizeHttpRequests(request -> request.requestMatchers(new AntPathRequestMatcher("/private/**"))
                .hasRole("USER"))
            .authorizeHttpRequests(request -> request.requestMatchers(new AntPathRequestMatcher("/public/**"))
                .permitAll())
            .httpBasic(Customizer.withDefaults())
            .build();
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

4. 方法安全配置

除了我們在 WebSecurityConfigurer 中定義的基於 URL 路徑的安全策略,我們還可以通過提供額外的配置文件來配置基於方法的安全策略。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfigurer 
  extends GlobalMethodSecurityConfiguration {
}

此配置啓用對 Spring Security 的 pre/post 註解的支持。如果需要額外的支持,還有其他屬性可用。有關 Spring Method Security 的更多信息,請參閲我們關於該主題的文章。

5. 使用 <em @WebMvcTest 測試控制器

當使用 Spring Security 中 <em @WebMvcTest 註解方法時,MockMvc 會自動配置必要的過濾器鏈,用於測試我們的安全配置。

由於 MockMvc 已經為我們配置好了,因此我們可以在測試中使用 <em @WithMockUser,而無需進行任何額外的配置。

@RunWith(SpringRunner.class)
@WebMvcTest(SecuredController.class)
public class SecuredControllerWebMvcIntegrationTest {

    @Autowired
    private MockMvc mvc;

    // ... other methods

    @WithMockUser(value = "spring")
    @Test
    public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
        mvc.perform(get("/private/hello").contentType(MediaType.APPLICATION_JSON))
          .andExpect(status().isOk());
    }
}

請注意,使用 @WebMvcTest 會告訴 Spring Boot 只實例化 Web 層,而不實例化整個上下文。因此,使用 @WebMvcTest 的控制器測試比其他方法運行速度更快。

使用@SpringBootTest測試控制器

在使用@SpringBootTest註解測試帶有Spring Security的控制器時,MockMvc的配置鏈需要明確配置。

使用SecurityMockMvcConfigurer提供的靜態springSecurity方法是實現這一目的的首選方式:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SecuredControllerSpringBootIntegrationTest {

    @Autowired
    private WebApplicationContext context;

    private MockMvc mvc;

    @Before
    public void setup() {
        mvc = MockMvcBuilders
          .webAppContextSetup(context)
          .apply(springSecurity())
          .build();
    }

    // ... other methods

    @WithMockUser("spring")
    @Test
    public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
        mvc.perform(get("/private/hello").contentType(MediaType.APPLICATION_JSON))
          .andExpect(status().isOk());
    }
}

7. 使用@SpringBootTest測試安全方法

@SpringBootTest無需任何額外配置即可測試安全方法。我們可以直接調用方法並根據需要使用@WithMockUser

@RunWith(SpringRunner.class)
@SpringBootTest
public class SecuredMethodSpringBootIntegrationTest {

    @Autowired
    private SecuredService service;

    @Test(expected = AuthenticationCredentialsNotFoundException.class)
    public void givenUnauthenticated_whenCallService_thenThrowsException() {
        service.sayHelloSecured();
    }

    @WithMockUser(username="spring")
    @Test
    public void givenAuthenticated_whenCallServiceWithSecured_thenOk() {
        assertThat(service.sayHelloSecured()).isNotBlank();
    }
}

8. 使用 @SpringBootTestTestRestTemplate 進行測試

TestRestTemplate 是編寫對受保護 REST 端點進行集成測試的便捷選項。

我們可以自動注入一個模板並設置憑據,然後再請求受保護的端點:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SecuredControllerRestTemplateIntegrationTest {

    @Autowired
    private TestRestTemplate template;

    // ... other methods

    @Test
    public void givenAuthRequestOnPrivateService_shouldSucceedWith200() throws Exception {
        ResponseEntity<String> result = template.withBasicAuth("spring", "secret")
          .getForEntity("/private/hello", String.class);
        assertEquals(HttpStatus.OK, result.getStatusCode());
    }
}

TestRestTemplate 具有靈活性,並提供許多有用的與安全相關的選項。有關 TestRestTemplate 的更多詳細信息,請參閲我們關於該主題的文章。

9. 結論

在本文中,我們探討了多種執行安全集成測試的方法。

我們研究瞭如何與 MVC 控制器和 REST 端點以及安全方法一起工作。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.