Spring Security для тестов интеграции Spring Boot
1. Вступление
Возможность выполнения интеграционных тестов без необходимости в отдельной среде интеграции является ценной функцией для любого программного стека. Плавная интеграция Spring Boot с Spring Security упрощает тестирование компонентов, взаимодействующих с уровнем безопасности.
В этом кратком руководстве мы рассмотрим использование@MockMvcTest и@SpringBootTest для выполнения интеграционных тестов безопасности.
2. зависимости
Давайте сначала внесем зависимости, которые нам понадобятся для нашего примера:
org.springframework.boot
spring-boot-starter-security
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.springframework.security
spring-security-test
test
Стартерыspring-boot-starter-web, spring-boot-starter-security, иspring-boot-starter-test предоставляют нам доступ к утилитам Spring MVC, Spring Security и Spring Boot test.
Кроме того, мы добавимspring-security-test, чтобы получить доступ к аннотации@WithMockUser, которую мы будем использовать.
3. Конфигурация веб-безопасности
Наша настройка веб-безопасности будет простой. Только аутентифицированные пользователи смогут получить доступ к путям, которые соответствуют/private/. Пути, соответствующие/public/, будут доступны любому пользователю:
@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
auth.inMemoryAuthentication()
.passwordEncoder(encoder)
.withUser("spring")
.password(encoder.encode("secret"))
.roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/private/**")
.authenticated()
.antMatchers("/public/**")
.permitAll()
.and()
.httpBasic();
}
}
4. Конфигурация безопасности метода
В дополнение к безопасности на основе URL-пути, которую мы определили в нашихWebSecurityConfigurer,, мы можем настроить безопасность на основе методов, предоставив дополнительный файл конфигурации:
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfigurer
extends GlobalMethodSecurityConfiguration {
}
Эта конфигурация включает поддержку аннотаций до и после Spring Security. Другие атрибуты также доступны, если требуется дополнительная поддержка. Для получения дополнительной информации о безопасности метода Spring взгляните на нашarticle on the topic.
5. Тестирование контроллеров с@WebMvcTest
При использовании подхода аннотации@WebMvcTest с Spring Security,MockMvc is automatically configured with the necessary filter chain требуется для проверки нашей конфигурации безопасности.
Поскольку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());
}
}
Обратите внимание, что использование@WebMvcTest укажет Spring Boot создать экземпляр только веб-уровня, а не всего контекста. Из-за этогоcontroller tests that use @WebMvcTest will run faster than with other approaches.
6. Тестирование контроллеров с@SpringBootTest
При использовании аннотации@SpringBootTest для тестирования контроллеров с помощью Spring Securityit’s necessary to explicitly configure the filter chain when setting up MockMvc.
Использование статического методаspringSecurity, предоставляемогоSecurityMockMvcConfigurer, является предпочтительным способом сделать это:
@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 не требует дополнительной настройки для тестирования защищенных методов. Мы можемsimply call the methods directly and use @WithMockUser as needed:
@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. Тестирование с@SpringBootTest иTestRestTemplate
TestRestTemplate - удобный вариант при написании интеграционных тестов для защищенных конечных точек REST.
Мы можем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 result = template.withBasicAuth("spring", "secret")
.getForEntity("/private/hello", String.class);
assertEquals(HttpStatus.OK, result.getStatusCode());
}
}
TestRestTemplate гибок и предлагает множество полезных опций, связанных с безопасностью. Чтобы узнать больше оTestRestTemplate, ознакомьтесь с нашимarticle on the topic.
9. Заключение
В этой статье мы рассмотрели несколько способов выполнения интеграционных тестов с включенной безопасностью.
Мы рассмотрели, как работать с конечными точками mvccontroller и REST, а также с защищенными методами.
Как обычно, весь исходный код для примера здесь может бытьfound over on GitHub.