SpringBoot統合テストのためのSpringSecurity
1. 序章
スタンドアロンの統合環境を必要とせずに統合テストを実行する機能は、あらゆるソフトウェアスタックにとって貴重な機能です。 SpringBootとSpringSecurityのシームレスな統合により、セキュリティレイヤーと相互作用するコンポーネントのテストが簡単になります。
このクイックチュートリアルでは、@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>
spring-boot-starter-web、 spring-boot-starter-security、、および spring-boot-starter-test starterは、Springへのアクセスを提供しますMVC、Spring Security、およびSpringBootテストユーティリティ。
さらに、使用する @WithMockUser アノテーションにアクセスするために、 spring-security-testを導入します。
3. Webセキュリティ構成
Webセキュリティの構成は簡単です。 / 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. メソッドのセキュリティ構成
WebSecurityConfigurer で定義したURLパスベースのセキュリティに加えて、追加の構成ファイルを提供することで、メソッドベースのセキュリティを構成できます。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfigurer
extends GlobalMethodSecurityConfiguration {
}
この構成により、SpringSecurityの事前/事後注釈のサポートが有効になります。 追加のサポートが必要な場合は、他の属性も使用できます。 Spring Method Securityの詳細については、トピックに関するの記事を参照してください。
5. @WebMvcTestを使用したコントローラーのテスト
SpringSecurityで@WebMvcTestアノテーションアプローチを使用する場合、 MockMvcは、セキュリティ構成をテストするために必要なフィルターチェーンで自動的に構成されます。
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 を使用すると、コンテキスト全体ではなくWebレイヤーのみをインスタンス化するようにSpringBootに指示されることに注意してください。 このため、@ WebMvcTestを使用するコントローラーテストは、他のアプローチよりも高速に実行されます。
6. @SpringBootTestを使用したコントローラーのテスト
@ Spring BootTest アノテーションを使用してSpringセキュリティでコントローラーをテストする場合、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. @SpringBootTestおよびTestRestTemplateを使用したテスト
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. 結論
この記事では、セキュリティ対応の統合テストを実行するいくつかの方法について説明しました。
mvccontrollerとRESTエンドポイント、およびセキュリティで保護されたメソッドを操作する方法を確認しました。
いつものように、ここでの例のすべてのソースコードは、GitHubで見つけることができます。