Spring Security Testを 使用して、Spring Security の背後に配線されているSpring MVC アプリのテストを作成する方法に関するドキュメントに従ってください。
これは、典型的なスプリング セキュリティ ワイヤリングを採用したバニラ スプリング ブート アプリケーションです。ここにメインの Application.java があります
@SpringBootApplication
public class Application {
private static final Logger log = LoggerFactory.getLogger(Application.class);
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
スプリングセキュリティの配線は次のとおりです。
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/","/sign_up").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.csrf()
.and()
.exceptionHandling()
.accessDeniedPage("/access_denied")
.and()
.logout()
.permitAll();
}
}
ご覧のとおり、"/" と "/sign_up" のリクエストを除いて、すべてのリクエストが認証される必要があります。アプリケーションをデプロイして、認証スキームが正常に機能することを確認しました。
ここからが興味深い部分です。Spring MVC テストの作成です。私が提供したリンクは、 spring-security-testフレームワークがモック ユーザー/セキュリティ コンテキストの挿入を許可するようなテストを作成するためのいくつかの良い方法を提供します。というアプローチをとりました
- モック UserDetails インターフェイスを定義し、
- SecurityContextFactory を使用して SecurityContext を作成します。
- テストの起動中にアプリケーション コンテキストに挿入する必要があります。
1. のコードは次のとおりです。
@WithSecurityContext(factory=WithMockUserDetailsSecurityContextFactory.class)
public @interface WithMockUserDetails {
String firstName() default "apil";
String lastName() default "tamang";
String password() default "test";
long id() default 999;
String email() default "apil@test.com";
}
2. のコードは次のとおりです。
final class WithMockUserDetailsSecurityContextFactory
implements WithSecurityContextFactory<WithMockUserDetails>{
@Override
public SecurityContext createSecurityContext(WithMockUserDetails mockUserDetails) {
/*
* Use an anonymous implementation for 'UserDetails' to return a
* mock authentication object, which is then set to the SecurityContext
* for the test runs.
*/
UserDetails principal=new UserDetails() {
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//another anonmyous interface implementation.
GrantedAuthority auth=new GrantedAuthority() {
@Override
public String getAuthority() {
return "ROLE_USER";
}
};
List<GrantedAuthority> authorities=new ArrayList<>();
authorities.add(auth);
return authorities;
}
@Override
public String getPassword() {
return mockUserDetails.password();
}
@Override
public String getUsername() {
return mockUserDetails.email();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
};
Authentication authentication=new
UsernamePasswordAuthenticationToken(principal,principal.getPassword(),principal.getAuthorities());
SecurityContext context= SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
return context;
}
}
最後に、テストクラスは次のとおりです。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = {Application.class})
@WebAppConfiguration
public class UserControllerTest {
@Autowired
private WebApplicationContext context;
@Autowired
private Filter springSecurityFilterChain;
private MockMvc mvc;
@Before
public void setup(){
mvc= MockMvcBuilders
.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
@Test
public void testRootIsOk() throws Exception {
mvc.perform(get("/"))
.andExpect(status().isOk());
}
@Test
public void expectRedirectToLogin() throws Exception {
mvc.perform(get("/testConnect"))
.andExpect(redirectedUrl("http://localhost/login"));
}
@Test
@WithMockUserDetails
public void testAuthenticationOkay() throws Exception {
mvc.perform(get("/testConnect"))
.andExpect(content().string("good request."));
}
}
テスト実行の出力:
- テスト 1 に合格します。
- 2 パスをテストします。
- テスト 3 は失敗します。出力が期待されていましたが、<> が得られました。
「SecurityContext」が適切に設定されていないため、テスト 3 が失敗した可能性が非常に高いです。ドキュメントによると、それはうまくいったはずです。私が逃したものがわからない。どんな助けでも大歓迎です。