次のように、従来の方法でSpringSecurityを使用してコントローラーに基本認証を設定しました。
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("user").password("user").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(....);
}
}
テストのポイントになると、私は@ WithMockUserを使用してテストに注釈を付けています。 GETのテストは次のようになります。
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeController.class)
public class SomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void test1() {
mockMvc.perform(get(...)).andExpect(...);
}
またはPOSTの場合は次のようになります。
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeController.class)
public class SomeControllerTest {
@Autowired
private MockMvc mockMvc;
@Test
public void test1() {
mockMvc.perform(post(...)).andExpect(...);
}
その後、予期しないことが起こります。
[〜#〜]質問[〜#〜]:何が起こっているのですか?この不正行為を修正する方法は?
Spring Securityがアクティブ化されているように見えますが、私のテストでは、使用されると予想される認証を使用していません。認証データを自分でモックする必要がありますか?
[〜#〜] edit [〜#〜]完全なconfigureメソッドは次のとおりです
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(URL1).hasAnyRole(ROLE_ADMIN)
.antMatchers(URL2).hasAnyRole(ROLE_USER)
.antMatchers(URL3).permitAll()
.and()
.httpBasic()
.and()
.csrf().disable();
}
この動作の背後には2つの理由があります。
@WithMockUser
アノテーションは、認証を実行するためのものではありません。すでに認証されているユーザーを作成します。デフォルトでは、彼の資格情報はuser
:password
です。@WebMvcTest
は実行されませんMySecurityConfig.Java。このアノテーションは、テスト用にSpring mockMvcオブジェクトセキュリティのデフォルトを使用を作成します。これらのセキュリティのデフォルトはorg.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration
によって適用されます。MySecurityConfig
メソッドにブレークポイントを設定し、デバッグモードでテストを再実行することで、これを再確認できます。ブレークポイントはヒットしません。問題1の解決
@WithMockUserアノテーションの機能にアプローチを変更するだけです。すでにログインしているユーザーを表示します。具体的なユーザー名、パスワード、およびロールを指定して、URLのセキュリティとロールの構成をテストすることは引き続き可能です。
問題2の解決
すべての統合テストの基本クラスを作成します。 SpringSecurityが適用されたmockMvcを構成します。 @SpringBootTest
アノテーションにも注意してください。今すぐテスト使用しますMySecurityConfig.Java
import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringRunner.class)
@SpringBootTest
public abstract class IT {
@Autowired
protected WebApplicationContext wac;
@Autowired
private FilterChainProxy springSecurityFilterChain;
protected MockMvc mockMvc;
@Before
public void applySecurity() {
this.mockMvc = webAppContextSetup(wac)
.apply(springSecurity(springSecurityFilterChain))
.build();
}
}
このようにテストを書き直してください。 http基本認証を使用すると仮定します。資格情報はテスト内で提供されます。注:モックユーザーアノテーションはありません。
package com.example.demo;
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import org.junit.Test;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
public class SomeControllerIT extends IT {
@Test
public void test1() throws Exception {
mockMvc.perform(get("/some")
.with(httpBasic("user", "user")))
.andExpect(MockMvcResultMatchers.content().string("hello"));
}
}
スプリングセキュリティの構成を使用してmockMVCテストを実行する方法は次のとおりです。USERロールの場合...
@RunWith(SpringRunner.class)
@WebMvcTest(controllers = SomeController.class)
public class SomeControllerTest {
@Autowired
private WebApplicationContext context;
@Autowired
private MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders
.webAppContextSetup(context)
.defaultRequest(get("/")
.with(user("user").password("password").roles("USER")))
.apply(springSecurity())
.build();
}
@Test
public void test1() {
mockMvc.perform(get(...)).andExpect(...);
}
}
この変更を行った後、GETテストが機能するはずです。
spring Securityは、POSTやDELETEなどのhttpリクエストに対してクロスサイトリクエストフォージェリ保護を提供するため、crsf()を使用してこれらの特定のテストを実行する必要があります。
@Test
public void shouldPost() {
mockMvc.perform(post(...)).with(csrf().asHeader())
.andExpect(...);
}