1. Introduction
1.介绍
The ability to execute integration tests without the need for a standalone integration environment is a valuable feature for any software stack. The seamless integration of Spring Boot with Spring Security makes it simple to test components that interact with a security layer.
在不需要独立集成环境的情况下执行集成测试的能力对于任何软件堆栈来说都是一个宝贵的功能。Spring Boot与Spring Security的无缝集成使得测试与安全层互动的组件变得简单。
In this quick tutorial, we’ll explore using @MockMvcTest and @SpringBootTest to execute security-enabled integration tests.
在这个快速教程中,我们将探索使用@MockMvcTest和@SpringBootTest来执行支持安全的集成测试。
2. Dependencies
2.依赖性
Let’s first bring in the dependencies we’ll need for our example:
让我们首先引入我们的例子所需要的依赖性。
<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>
The spring-boot-starter-web, spring-boot-starter-security, and spring-boot-starter-test starters provide us with access to Spring MVC, Spring Security, and the Spring Boot test utilities.
spring-boot-starter-web, spring-boot-starter-security, 和spring-boot-starter-teststarters使我们能够访问Spring MVC, Spring Security 和 Spring Boot测试实用程序.
In addition, we’ll bring in spring-security-test in order to get access to the @WithMockUser annotation that we’ll be using.
此外,我们将引入spring-security-test,以便获得我们将要使用的@WithMockUser注解。
3. Web Security Configuration
3.网络安全配置
Our web security configuration will be straightforward. Only authenticated users will be able to access paths that match /private/** . Paths that match /public/** will be available for any user:
我们的网络安全配置将是简单明了的。只有经过认证的用户才能访问与/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 {
http.authorizeRequests()
.antMatchers("/private/**")
.hasRole("USER")
.antMatchers("/public/**")
.permitAll()
.and()
.httpBasic();
return http.build();
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
4. Method Security Configuration
4.方法安全配置
In addition to the URL path-based security we defined in our WebSecurityConfigurer, we can configure method-based security by providing an additional configuration file:
除了我们在WebSecurityConfigurer中定义的基于URL路径的安全之外,我们可以通过提供一个额外的配置文件来配置基于方法的安全。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfigurer
extends GlobalMethodSecurityConfiguration {
}
This configuration enables support for Spring Security’s pre/post annotations. Other attributes are available as well if additional support is required. For more information on Spring Method Security, take a look at our article on the topic.
这种配置能够支持Spring Security的前/后注释。如果需要额外的支持,其他属性也是可用的。有关Spring方法安全的更多信息,请查看我们关于该主题的文章。
5. Testing Controllers With @WebMvcTest
5.使用@WebMvcTest测试控制器
When using the @WebMvcTest annotation approach with Spring Security, MockMvc is automatically configured with the necessary filter chain required to test our security configuration.
当使用@WebMvcTest注解方法和Spring Security时,MockMvc被自动配置为必要的过滤器链,以测试我们的安全配置。
Because MockMvc is configured for us, we’re able to use @WithMockUser for our tests without any additional configuration:
因为MockMvc是为我们配置的,所以我们能够在测试中使用@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());
}
}
Note that using @WebMvcTest will tell Spring Boot to instantiate only the web layer and not the entire context. Because of this, controller tests that use @WebMvcTest will run faster than with other approaches.
请注意,使用@WebMvcTest将告诉Spring Boot只对Web层进行实例化,而不是整个环境。正因为如此,使用@WebMvcTest的controller测试将比其他方法运行得更快。
6. Testing Controllers With @SpringBootTest
6.用@SpringBootTest测试控制器
When using @SpringBootTest annotation to test controllers with Spring Security, it’s necessary to explicitly configure the filter chain when setting up MockMvc.
当使用@SpringBootTest注解来测试带有Spring Security的控制器时,有必要在设置MockMvc时明确配置过滤器链。
Using the static springSecurity method provided by SecurityMockMvcConfigurer is the preferred way to do this:
使用由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. Testing Secured Methods With @SpringBootTest
7.用@SpringBootTest测试安全的方法
@SpringBootTest doesn’t require any additional configuration to test secured methods. We can simply call the methods directly and use @WithMockUser as needed:
@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. Testing With @SpringBootTest and TestRestTemplate
8.使用@SpringBootTest和TestRestTemplate进行测试
TestRestTemplate is a convenient option when writing integration tests for secured REST endpoints.
TestRestTemplate是为安全的REST端点编写集成测试时的一个方便选项。
We can simply autowire a template and set credentials before requesting secured endpoints:
我们可以简单地自动连接一个模板,并在请求安全端点之前设置凭证:。
@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 is flexible and offers many useful security-related options. For more details on TestRestTemplate, check out our article on the topic.
TestRestTemplate很灵活,提供了许多有用的安全相关选项。有关TestRestTemplate的更多细节,请查看我们关于该主题的文章。
9. Conclusion
9.结论
In this article, we looked at several ways of executing security-enabled integration tests.
在这篇文章中,我们看了几种执行支持安全的集成测试的方法。
We looked at how to work with MVC controller and REST endpoints and also with secured methods.
我们研究了如何使用MVC控制器和REST端点以及安全方法。
As usual, all source code for the example here can be found over on GitHub.
像往常一样,这里的例子的所有源代码都可以在GitHub上找到过。